2013-08-21 55 views
3

我試圖模擬Windows 7 X64(SP1)上的syscall指令是如何工作的,所以我使用MinGW64編寫了一個64位GCC示例。據我所知,對於Windows,所有系統調用入口點都在ntdll.dll或ntdll32.dll中(在這種情況下,我們只關心ntdll.dll)。如何在Windows 7 X64 SP1(x64模式)下執行直接系統調用?

Status = NtCreateFile(&FileHandle,      // returned file handle 
         (GENERIC_WRITE | SYNCHRONIZE), // desired access 
         &ObjectAttributes,    // ptr to object attributes 
         &Iosb,       // ptr to I/O status block 
         0,        // allocation size 
         FILE_ATTRIBUTE_NORMAL,   // file attributes 
         0,        // share access 
         FILE_SUPERSEDE,     // create disposition 
         FILE_SYNCHRONOUS_IO_NONALERT,  // create options 
         NULL,        // ptr to extended attributes 
         0);        // length of ea buffer 

這是用C編寫的源代碼原件,然後我現在氣

asm volatile 
(
    "leaq %4, %%r9\n\t" 
    "leaq %3, %%r8\n\t" 
    "movq %2, %%rdx\n\t" 
    "leaq %1, %%rcx\n\t" 
    "movq %11,0x50(%%rsp)\n\t" 
    "movq %10,0x48(%%rsp)\n\t" 
    "movq %9, 0x40(%%rsp)\n\t" 
    "movq %8, 0x38(%%rsp)\n\t" 
    "movq %7, 0x30(%%rsp)\n\t" 
    "movq %6, 0x28(%%rsp)\n\t" 
    "movq %5, 0x20(%%rsp)\n\t" 
    "movq %%r9, 0x18(%%rsp)\n\t" 
    "movq %%r8, 0x10(%%rsp)\n\t" 
    "movq %%rdx, 0x8(%%rsp)\n\t" 
    "movq %%rcx, (%%rsp)\n\t" 
    "movq __imp_NtCreateFile(%%rip), %%rax\n\t" 
    "call *%%rax\n\t" 
    : "=a"(Status) 
    : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAttributes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) 
    : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" 
); 

重寫它爲止,該計劃按預期工作:它創建一個文本文件,寫的東西文件。

我使用WinDbg來拆卸NTDLL!NtCreateFile和

"movq $0x52, %%rax\n\t" 
    "movq %%rcx, %%r10\n\t" 
    "syscall\n\t" 
    "ret\n\t" 

我說我的計劃之內的這部分代碼爲

asm volatile 
(
    "leaq %4, %%r9\n\t" 
    "leaq %3, %%r8\n\t" 
    "movq %2, %%rdx\n\t" 
    "leaq %1, %%rcx\n\t" 
    "movq %11,0x50(%%rsp)\n\t" 
    "movq %10,0x48(%%rsp)\n\t" 
    "movq %9, 0x40(%%rsp)\n\t" 
    "movq %8, 0x38(%%rsp)\n\t" 
    "movq %7, 0x30(%%rsp)\n\t" 
    "movq %6, 0x28(%%rsp)\n\t" 
    "movq %5, 0x20(%%rsp)\n\t" 
    "movq %%r9, 0x18(%%rsp)\n\t" 
    "movq %%r8, 0x10(%%rsp)\n\t" 
    "movq %%rdx, 0x8(%%rsp)\n\t" 
    "movq %%rcx, (%%rsp)\n\t" 
    "movq $0x52, %%rax\n\t" 
    "movq %%rcx, %%r10\n\t" 
    "syscall\n\t" 
    : "=a"(Status) 
    : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAttributes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) 
    : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" 
); 

只鋸(rewrited作爲氣體&牛逼格式)現在狀態總是返回值'0xc000000d',程序失敗。現在我有幾個困惑的問題:

  1. 這裏存儲在用戶模式堆棧中的參數如何進入內核模式?因爲我在NtDll!NtCreateFile中看不到任何東西。

  2. 如何將正確的返回值分配回%% rax?這部分也是在disassmebler內部的錯誤。

  3. 如何讓我的代碼在執行直接系統調用時能夠工作?

非常感謝您的大力幫助。


OK,在這裏展示工作代碼

asm volatile 
(
    "leaq %4, %%r9\n\t" 
    "leaq %3, %%r8\n\t" 
    "movq %2, %%rdx\n\t" 
    "leaq %1, %%rcx\n\t" 
    "movq %11,0x50(%%rsp)\n\t" 
    "movq %10,0x48(%%rsp)\n\t" 
    "movq %9, 0x40(%%rsp)\n\t" 
    "movq %8, 0x38(%%rsp)\n\t" 
    "movq %7, 0x30(%%rsp)\n\t" 
    "movq %6, 0x28(%%rsp)\n\t" 
    "movq %5, 0x20(%%rsp)\n\t" 
    "push $_end \n\t" 
    "movq %%rcx,%%r10\n\t" 
    "movq $0x52,%%rax\n\t" 
    "syscall\n\t" 
    "ret\n\t" 
    "_end:\n\t" 
    : "=a"(Status) 
    : "m"(FileHandle), "g"(GENERIC_WRITE | SYNCHRONIZE),"m"(ObjectAttributes),"m"(Iosb),"g"(0),"g"(FILE_ATTRIBUTE_NORMAL),"g"(0),"g"(FILE_SUPERSEDE),"g"(FILE_SYNCHRONOUS_IO_NONALERT),"g"(NULL),"g"(0) 
    : "%rcx", "%rdx", "%r8", "%r9", "%r10","%r11" 
); 

它是不是真的痛到模擬的呼叫/ RET。在這裏,我使用了Linus在他的Linux 0.11中使用過的解決方法。

+0

你究竟在做什麼?你是否正在努力解決如何在asm中調用NtCreateFile?或者你是否試圖實現NtCreateFile? –

+0

第二個,實現NtCreateFile進行實驗 –

+0

在這種情況下,放棄嘗試用asm編寫調用。這是混淆的問題。用C編寫調用並將實現寫入asm。你爲什麼甚至試圖做到這一點。這似乎毫無意義,我希望它失敗。 –

回答

3

我認爲你對堆棧的深度是錯誤的。 許多參數都通過堆棧傳遞。如果庫調用是在系統調用之間,系統調用期望它們到達它們的位置。

如果您跳過庫調用並自己執行系統調用(您只需要做實驗,而不是用於高效工作!),那麼堆棧中就有一個項缺失。

因此,將一個虛擬值推入堆棧或調整偏移量。

詳細,下面的原代碼發生了:

  • 你把參數堆棧(高達movq %%rcx, (%%rsp))。您執行call__imp_NtCreateFile這將返回地址放入堆棧,並執行%tip到庫函數的傳輸。
  • 然後庫函數本質上執行系統調用。
  • 內核然後希望數據遠離堆棧頂部一個項目,因爲所述調用添加了一個項目。

如果您自己執行系統調用,則必須放入另一項以補償此返回地址,該地址將移動內核的堆棧視圖。

+0

非常感謝您的幫助,我現在糾正了錯誤。裸函數在X86/X64中不支持,所以我不得不刪除由編譯器manullay生成的序言/結語序列,測試顯示您的點完全正確。關於 –

+0

你給我一個黑暗中的光。我現在解決了它。 –

+0

✓可以用來表明答案已經解決了問題。 – glglgl