梦幻的彼岸 发表于 2022-2-11 17:41:51

WindowsNoExec -滥用现有指令,在不分配可执行内存的情况下执行任意代码

本帖最后由 梦幻的彼岸 于 2022-2-11 17:47 编辑

翻译
原文地址:https://www.x86matthew.com/view_post?id=windows_no_exec
功能:滥用现有指令,在不分配可执行内存的情况下执行任意代码

static/image/hrline/1.gif
这个概念验证允许我们 "重新使用 "ntdll.dll中的现有指令来执行我们自己的代码。目标代码只存在于数据部分,这意味着这种方法规避了非可执行内存的保护。这种方法的一个副作用意味着它很难被调试,并绕过了静态代码分析。

有趣的是,这种技术只需要一个API - RtlAddVectoredExceptionHandler。我的代码还使用了GetModuleHandle来检索ntdll.dll的基本地址,但如果有必要,这也是一个很容易重新创建的函数。如果你有足够的创造力,你也可以通过扫描ntdll.dll来找到vectored异常处理程序列表指针,然后手动添加条目,从而消除RtlAddVectoredExceptionHandler调用。

这个代码的工作原理如下:
1. 创建一个数据结构,包含所有我们要执行的汇编指令。
2. 在ntdll.dll的代码部分搜索上述每条指令,并存储其地址。
3. 使用RtlAddVectoredExceptionHandler在我们的程序中添加一个自定义的异常处理程序。
4. 使用int 3触发一个断点。
5. 现在程序已经进入了我们的自定义异常处理程序。存储原来的线程上下文以备后用。
6. 将EIP寄存器设置为我们列表中的第一个目标指令(在ntdll.dll中)。
7. 如果当前指令是一个 "调用",使用Dr0调试寄存器在调用后的指令上设置一个硬件断点--我们要 "跨过 "调用。否则,用EFlags |= 0x100设置单步标志,在下一条指令上断开。
8. 更新当前指令所需的任何其他寄存器的值。
9. 使用EXCEPTION_CONTINUE_EXECUTION继续执行。下一条指令将引发另一个异常,我们将从第6步继续,直到所有的指令都依次运行完毕。
10. 在所有的目标指令执行完毕后,恢复步骤#5中的原始线程上下文,以继续程序的原始流程。
下面的数据结构将调用MessageBoxA:
InstructionEntryStruct Global_InstructionList[] =
{
      // allocate 1kb buffer for messagebox title using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set messagebox title to "www.x86matthew.com"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '8' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '8', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '6' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '6', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'h' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'h', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'c' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'c', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // store messagebox title ptr in edi register
      { "mov edi, eax", { 0x8B, 0xF8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },

      // allocate 1kb buffer for messagebox text using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set messagebox text to "A message box from ntdll.dll"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'A' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'A', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 's' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 's', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 's' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 's', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'f' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'f', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'r' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'r', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'n' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'n', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // call MessageBoxA
      { "push ecx", { 0x51 }, 1, 0, 0, 0, MB_OK, 0, 0, 0, FLAG_ECX },
      { "push edi", { 0x57 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "call eax ; (MessageBoxA)", { 0xFF, 0xD0 }, 2, 0, (DWORD)MessageBoxA, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
};

该结构头包含以下字段:
struct InstructionEntryStruct
{
      char *pLabel;

      BYTE bInstruction;
      DWORD dwInstructionLength;

      DWORD dwInstructionAddr;

      DWORD dwEax;
      DWORD dwEbx;
      DWORD dwEcx;
      DWORD dwEdx;
      DWORD dwEdi;
      DWORD dwEsi;
      DWORD dwInstructionFlags;
};
pLabel
这个字段仅用于记录/调试的目的。

bInstruction
这个字段包含目标指令的操作码--例如0x50用于推送eax。

dwInstructionLength
bInstruction字段的长度。

dwInstructionAddr
这个字段由程序填充 - ntdll.dll被扫描以找到匹配指令的地址。

dwEax / dwEbx / dwEcx / dwEdx / dwEdi / dwEsi
这些字段在当前指令执行前设置指定的寄存器值。

dwInstructionFlags
这个字段指定哪些寄存器的值应该被更新(见上文)。它还用于指定当前指令是否为 "调用"。

重要的是要注意我们选择的指令操作码。例如,如果我们想加入一条push 0x12345678指令,我们可以这样做:
{ "push 0x12345678", { 0x68, 0x44, 0x33, 0x22, 0x11 }, 5, 0, 0, 0, 0, 0, 0, 0, 0 }
...但这不会起作用。这是因为ntdll.dll非常不可能在代码部分包含一个包含的序列。这段代码利用了我们可以在指令执行前在异常处理程序内操作寄存器这一事实,这意味着我们可以用以下方式代替:
{ "push eax", { 0x50 }, 1, 0, 0x11223344, 0, 0, 0, 0, 0, FLAG_EAX }
上面的条目只依赖于在ntdll.dll代码部分找到一个0x50(push eax)的字节。eax寄存器的值将在指令执行前被异常处理程序设置为0x11223344。

下面的数据结构演示了一个稍微复杂的例子--这创建了一个文件(x86matthew.txt),并将 "由ntdll创建的文本文件 "写入返回的句柄。
InstructionEntryStruct Global_InstructionList[] =
{
      // allocate 1kb buffer for filename using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set filename to "x86matthew.txt"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '8' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '8', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '6' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '6', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'h' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'h', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // call CreateFileA
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, FILE_ATTRIBUTE_NORMAL, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, CREATE_ALWAYS, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GENERIC_WRITE, 0, 0, 0, FLAG_ECX },
      { "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "call eax ; (CreateFileA)", { 0xFF, 0xD0 }, 2, 0, (DWORD)CreateFileA, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // store file handle in esi register
      { "mov esi, eax", { 0x8B, 0xF0 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 }, // mov esi, eax (esi=hFile)

      // allocate 1kb buffer for file content using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set file content buffer to "Text file created by ntdll"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'T' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'T', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'f' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'f', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'i' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'i', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'c' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'c', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'r' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'r', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'y' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'y', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'n' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'n', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // call WriteFile (and allocate a local variable on the stack for the lpNumberOfBytesWritten value)
      { "push ebp", { 0x55 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push 0", { 0x6A, 0x00 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov ebp, esp", { 0x8B, 0xEC }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "push ebp", { 0x55 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 26, 0, 0, 0, FLAG_ECX },
      { "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push esi", { 0x56 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "call eax ; (WriteFile)", { 0xFF, 0xD0 }, 2, 0, (DWORD)WriteFile, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
      { "pop ecx", { 0x59 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "pop ebp", { 0x5D }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // call CloseHandle
      { "push esi", { 0x56 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "call eax ; (CloseHandle)", { 0xFF, 0xD0 }, 2, 0, (DWORD)CloseHandle, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
};
以下是完整的代码:
#include <stdio.h>
#include <windows.h>

#define FLAG_EAX 0x00000001
#define FLAG_EBX 0x00000002
#define FLAG_ECX 0x00000004
#define FLAG_EDX 0x00000008
#define FLAG_EDI 0x00000010
#define FLAG_ESI 0x00000020
#define FLAG_CALL 0x00000040

struct InstructionEntryStruct
{
      char *pLabel;

      BYTE bInstruction;
      DWORD dwInstructionLength;

      DWORD dwInstructionAddr;

      DWORD dwEax;
      DWORD dwEbx;
      DWORD dwEcx;
      DWORD dwEdx;
      DWORD dwEdi;
      DWORD dwEsi;
      DWORD dwInstructionFlags;
};

DWORD dwGlobal_CurrInstruction = 0;
CONTEXT Global_OrigContext;

InstructionEntryStruct Global_InstructionList[] =
{
      // allocate 1kb buffer for messagebox title using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set messagebox title to "www.x86matthew.com"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '8' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '8', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '6' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '6', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'h' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'h', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'w' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'w', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'c' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'c', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // store messagebox title ptr in edi register
      { "mov edi, eax", { 0x8B, 0xF8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },

      // allocate 1kb buffer for messagebox text using GlobalAlloc
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 1024, 0, 0, 0, FLAG_ECX },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, GMEM_FIXED, 0, 0, 0, FLAG_ECX },
      { "call eax ; (GlobalAlloc)", { 0xFF, 0xD0 }, 2, 0, (DWORD)GlobalAlloc, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },

      // set messagebox text to "A message box from ntdll.dll"
      { "mov ebx, eax", { 0x8B, 0xD8 }, 2, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'A' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'A', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 's' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 's', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 's' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 's', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'a' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'a', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'g' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'g', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'e' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'e', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'b' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'b', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'x' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'x', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'f' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'f', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'r' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'r', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'o' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'o', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'm' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'm', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: ' ' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, ' ', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'n' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'n', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 't' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 't', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: '.' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '.', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'd' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'd', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; character: 'l' ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, 'l', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "mov byte ptr , dl ; (null) ", { 0x88, 0x13 }, 2, 0, 0, 0, 0, '\0', 0, 0, FLAG_EDX },
      { "inc ebx", { 0x43 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },

      // call MessageBoxA
      { "push ecx", { 0x51 }, 1, 0, 0, 0, MB_OK, 0, 0, 0, FLAG_ECX },
      { "push edi", { 0x57 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push eax", { 0x50 }, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
      { "push ecx", { 0x51 }, 1, 0, 0, 0, 0, 0, 0, 0, FLAG_ECX },
      { "call eax ; (MessageBoxA)", { 0xFF, 0xD0 }, 2, 0, (DWORD)MessageBoxA, 0, 0, 0, 0, 0, FLAG_EAX | FLAG_CALL },
};

LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *pExceptionInfo)
{
      InstructionEntryStruct *pCurrInstruction = NULL;

      // ensure this is a breakpoint / single step exception
      if(pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_BREAKPOINT && pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP)
      {
                // this is not the exception that we expected - pass this exception to the next handler
                return EXCEPTION_CONTINUE_SEARCH;
      }

      // reset hardware breakpoints
      pExceptionInfo->ContextRecord->Dr0 = 0;
      pExceptionInfo->ContextRecord->Dr7 = 0;

      if(dwGlobal_CurrInstruction == 0)
      {
                // store original context
                memcpy((void*)&Global_OrigContext, (void*)pExceptionInfo->ContextRecord, sizeof(CONTEXT));
      }
      else if(dwGlobal_CurrInstruction >= (sizeof(Global_InstructionList) / sizeof(Global_InstructionList)))
      {
                // finished executing all instructions - restore original context
                memcpy((void*)pExceptionInfo->ContextRecord, (void*)&Global_OrigContext, sizeof(CONTEXT));

                // move to the next instruction (after int3)
                pExceptionInfo->ContextRecord->Eip++;

                // continue execution
                return EXCEPTION_CONTINUE_EXECUTION;
      }

      // get current instruction entry
      pCurrInstruction = &Global_InstructionList;

      // set instruction ptr to next instruction
      pExceptionInfo->ContextRecord->Eip = pCurrInstruction->dwInstructionAddr;

      // check register flags
      if(pCurrInstruction->dwInstructionFlags & FLAG_EAX)
      {
                // set eax
                printf("<InternalExHandler> mov eax, 0x%x\n", pCurrInstruction->dwEax);
                pExceptionInfo->ContextRecord->Eax = pCurrInstruction->dwEax;
      }
      else if(pCurrInstruction->dwInstructionFlags & FLAG_EBX)
      {
                // set ebx
                printf("<InternalExHandler> mov ebx, 0x%x\n", pCurrInstruction->dwEbx);
                pExceptionInfo->ContextRecord->Ebx = pCurrInstruction->dwEbx;
      }
      else if(pCurrInstruction->dwInstructionFlags & FLAG_ECX)
      {
                // set ecx
                printf("<InternalExHandler> mov ecx, 0x%x\n", pCurrInstruction->dwEcx);
                pExceptionInfo->ContextRecord->Ecx = pCurrInstruction->dwEcx;
      }
      else if(pCurrInstruction->dwInstructionFlags & FLAG_EDX)
      {
                // set edx
                printf("<InternalExHandler> mov edx, 0x%x\n", pCurrInstruction->dwEdx);
                pExceptionInfo->ContextRecord->Edx = pCurrInstruction->dwEdx;
      }
      else if(pCurrInstruction->dwInstructionFlags & FLAG_EDI)
      {
                // set edi
                printf("<InternalExHandler> mov edi, 0x%x\n", pCurrInstruction->dwEdi);
                pExceptionInfo->ContextRecord->Edi = pCurrInstruction->dwEdi;
      }
      else if(pCurrInstruction->dwInstructionFlags & FLAG_ESI)
      {
                // set esi
                printf("<InternalExHandler> mov esi, 0x%x\n", pCurrInstruction->dwEsi);
                pExceptionInfo->ContextRecord->Esi = pCurrInstruction->dwEsi;
      }

      // print current instruction label
      printf("<ntdll: 0x%08X> %s\n", pCurrInstruction->dwInstructionAddr, pCurrInstruction->pLabel);

      // check if this is a 'call' instruction
      if(pCurrInstruction->dwInstructionFlags & FLAG_CALL)
      {
                // set a hardware breakpoint on the first instruction after the 'call'
                pExceptionInfo->ContextRecord->Dr0 = pCurrInstruction->dwInstructionAddr + pCurrInstruction->dwInstructionLength;
                pExceptionInfo->ContextRecord->Dr7 = 1;
      }
      else
      {
                // single step
                pExceptionInfo->ContextRecord->EFlags |= 0x100;
      }

      // move to the next instruction
      dwGlobal_CurrInstruction++;

      // continue execution
      return EXCEPTION_CONTINUE_EXECUTION;
}

DWORD GetModuleCodeSection(DWORD dwModuleBase, DWORD *pdwCodeSectionStart, DWORD *pdwCodeSectionLength)
{
      IMAGE_DOS_HEADER *pDosHeader = NULL;
      IMAGE_NT_HEADERS *pNtHeader = NULL;
      IMAGE_SECTION_HEADER *pCurrSectionHeader = NULL;
      char szCurrSectionName;
      DWORD dwFound = 0;
      DWORD dwCodeSectionStart = 0;
      DWORD dwCodeSectionLength = 0;

      // get dos header ptr (start of module)
      pDosHeader = (IMAGE_DOS_HEADER*)dwModuleBase;
      if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
      {
                return 1;
      }

      // get nt header ptr
      pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDosHeader + pDosHeader->e_lfanew);
      if(pNtHeader->Signature != IMAGE_NT_SIGNATURE)
      {
                return 1;
      }

      // loop through all sections
      for(DWORD i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
      {
                // get current section header
                pCurrSectionHeader = (IMAGE_SECTION_HEADER*)((BYTE*)pNtHeader + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER)));

                // pCurrSectionHeader->Name is not null terminated if all 8 characters are used - copy it to a larger local buffer
                memset(szCurrSectionName, 0, sizeof(szCurrSectionName));
                memcpy(szCurrSectionName, pCurrSectionHeader->Name, sizeof(pCurrSectionHeader->Name));

                // check if this is the main code section
                if(strcmp(szCurrSectionName, ".text") == 0)
                {
                        // found code section
                        dwFound = 1;
                        dwCodeSectionStart = dwModuleBase + pCurrSectionHeader->VirtualAddress;
                        dwCodeSectionLength = pCurrSectionHeader->SizeOfRawData;

                        break;
                }
      }

      // ensure the code section was found
      if(dwFound == 0)
      {
                return 1;
      }

      // store values
      *pdwCodeSectionStart = dwCodeSectionStart;
      *pdwCodeSectionLength = dwCodeSectionLength;

      return 0;
}

DWORD ScanForInstructions()
{
      DWORD dwInstructionCount = 0;
      DWORD dwCurrSearchPos = 0;
      DWORD dwBytesRemaining = 0;
      DWORD dwFoundAddr = 0;
      DWORD dwCodeSectionStart = 0;
      DWORD dwCodeSectionLength = 0;

      // calculate instruction count
      dwInstructionCount = sizeof(Global_InstructionList) / sizeof(Global_InstructionList);

      // find ntdll code section range
      if(GetModuleCodeSection((DWORD)GetModuleHandle("ntdll.dll"), &dwCodeSectionStart, &dwCodeSectionLength) != 0)
      {
                return 1;
      }

      // scan for instructions
      for(DWORD i = 0; i < dwInstructionCount; i++)
      {
                // check if an address has already been found for this instruction
                if(Global_InstructionList.dwInstructionAddr != 0)
                {
                        continue;
                }

                // find this instruction in the ntdll code section
                dwCurrSearchPos = dwCodeSectionStart;
                dwBytesRemaining = dwCodeSectionLength;
                dwFoundAddr = 0;
                for(;;)
                {
                        // check if the end of the code section has been reached
                        if(Global_InstructionList.dwInstructionLength > dwBytesRemaining)
                        {
                              break;
                        }

                        // check if the instruction exists here
                        if(memcmp((void*)dwCurrSearchPos, (void*)Global_InstructionList.bInstruction, Global_InstructionList.dwInstructionLength) == 0)
                        {
                              dwFoundAddr = dwCurrSearchPos;
                              break;
                        }

                        // update search indexes
                        dwCurrSearchPos++;
                        dwBytesRemaining--;
                }

                // ensure the opcode was found
                if(dwFoundAddr == 0)
                {
                        printf("Error: Instruction not found in ntdll: '%s'\n", Global_InstructionList.pLabel);

                        return 1;
                }

                // store address
                Global_InstructionList.dwInstructionAddr = dwFoundAddr;

                // copy this instruction address to any other matching instructions in the list
                for(DWORD ii = 0; ii < dwInstructionCount; ii++)
                {
                        // check if the instruction lengths match
                        if(Global_InstructionList.dwInstructionLength == Global_InstructionList.dwInstructionLength)
                        {
                              // check if the instruction opcodes match
                              if(memcmp(Global_InstructionList.bInstruction, Global_InstructionList.bInstruction, Global_InstructionList.dwInstructionLength) == 0)
                              {
                                        // copy instruction address
                                        Global_InstructionList.dwInstructionAddr = Global_InstructionList.dwInstructionAddr;
                              }
                        }
                }
      }

      return 0;
}

int main()
{
      PVOID (WINAPI *RtlAddVectoredExceptionHandler)(DWORD dwFirstHandler, void *pExceptionHandler);
      DWORD dwThreadID = 0;
      HANDLE hThread = NULL;

      printf("WindowsNoExec - www.x86matthew.com\n\n");

      // get RtlAddVectoredExceptionHandler function ptr
      RtlAddVectoredExceptionHandler = (void *(__stdcall *)(unsigned long,void *))GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlAddVectoredExceptionHandler");
      if(RtlAddVectoredExceptionHandler == NULL)
      {
                return 1;
      }

      printf("Adding exception handler...\n");

      // add exception handler
      if(RtlAddVectoredExceptionHandler(1, (void*)ExceptionHandler) == NULL)
      {
                return 1;
      }

      printf("Scanning ntdll to populate instruction list...\n");

      // scan for instructions
      if(ScanForInstructions() != 0)
      {
                return 1;
      }

      printf("Starting...\n\n");

      // breakpoint to trigger exception handler
      _asm int 3

      printf("\nFinished\n");

      return 0;
}
页: [1]
查看完整版本: WindowsNoExec -滥用现有指令,在不分配可执行内存的情况下执行任意代码