我的操作系统是 Windows 7 64 位,我的处理器是在 x64 架构上运行的 Intel Core i7-4700MQ。我的程序是 32 位的。
最近,我在这里阅读了一篇文章,描述了如何在 C 中将 main 函数简单地编写为整数、字符、浮点数、双精度数等的常量数组是可能和合法的。 这篇文章在编写过程中一步一步地进行在 linux 中汇编,然后将其转换为常量整数数组以打印“Hello world!\n\0”。我以前从未见过这样的程序,所以我决定制作一个可以在 Windows 上运行的程序会很酷。
在我的程序中,我显示了一个 ANSI 样式的 MessageBox,标题为“Made by CaptainObvious!\n\0”和消息“C 和程序集是给真正的人\n\0”。我的 C 程序中有可用的内联汇编代码,如下所示:
int main( )
{
__asm__
(
"sub $0x10, %esp;\n"
"movl $0x0, 0x0(%esp);\n"
"lea message, %eax;\n"
"movl %eax, 0x4(%esp);\n"
"lea title, %eax;\n"
"movl %eax, 0x8(%esp);\n"
"movl $0x00000040, 0xc(%esp);\n"
"call _MessageBoxA@16;\n"
"movl $0, %eax;\n"
"leave;\n"
"ret;\n"
"message: .ascii \"C and assembly are for real men.\\n\\0\";"
"title: .ascii \"Made by CaptainObvious!\\n\\0\";"
);
return 0;
}
同样为了确保我可以实现文章中使用的技术,我编写了一个简单的操作码数组,用于在执行后立即返回值 10。测试成功,该数组如下所示:
const char main[] = { 0x55, 0x89, 0xe5, 0x83, 0xe4, 0xf0, 0x83, 0xec, 0x10, 0xe8, 0, 0, 0, 0, 0xb8, 10, 0, 0, 0, 0xc9, 0xc3 };
然而,当我尝试将更复杂的程序转换为整数常量数组时,我的程序无法使用 SIGILL(非法指令)执行。这是来自 gdb 的相关反汇编输出:
0x00403040 and $0xffffff89,%ebp
0x00403043 push %ebp
0x00403044 add %ch,%al
0x00403046 lock in $0x83,%al ; <--- SIGILL
; ...
看到 gdb 的反汇编输出,我怀疑我的整数数组是错误的,但是虽然我发现了一些错误,但它仍然抛出与上面显示的完全相同的 SIGILL 异常。这是当前的整数数组:
const unsigned int main[] =
{
0x5589e583, 0xe4f0e800, 0x00000083, 0xec10c704, 0x24000000,
0x008d053d, 0x00000089, 0x4424048d, 0x055f0000, 0x00894424,
0x08c74424, 0x0c400000, 0x00e80000, 0x0000b800, 0x000000c9,
0xc3432061, 0x6e642061, 0x7373656d, 0x626c7920, 0x61726520,
0x666f7220, 0x7265616c, 0x206d656e, 0x2e0a004d, 0x61646520,
0x62792043, 0x68726973, 0x204f2754, 0x6f6f6c65, 0x210a00b8,
0x00000000, 0xc9c39090
};
目前为了获取十六进制操作码,我使用 MinGW 包附带的 objdump.exe 程序转储了我的程序的 .text 部分。这是我的程序在转储 .text 部分时的输出:
Disassembly of section .text:
00000000 <_main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: e8 00 00 00 00 call b <_main+0xb>
b: 83 ec 10 sub $0x10,%esp
e: c7 04 24 00 00 00 00 movl $0x0,(%esp)
15: 8d 05 3d 00 00 00 lea 0x3d,%eax
1b: 89 44 24 04 mov %eax,0x4(%esp)
1f: 8d 05 5f 00 00 00 lea 0x5f,%eax
25: 89 44 24 08 mov %eax,0x8(%esp)
29: c7 44 24 0c 40 00 00 movl $0x40,0xc(%esp)
30: 00
31: e8 00 00 00 00 call 36 <_main+0x36>
36: b8 00 00 00 00 mov $0x0,%eax
3b: c9 leave
3c: c3 ret
0000003d <message>:
3d: 43 inc %ebx
3e: 20 61 6e and %ah,0x6e(%ecx)
41: 64 20 61 73 and %ah,%fs:0x73(%ecx)
45: 73 65 jae ac <title+0x4d>
47: 6d insl (%dx),%es:(%edi)
48: 62 6c 79 20 bound %ebp,0x20(%ecx,%edi,2)
4c: 61 popa
4d: 72 65 jb b4 <title+0x55>
4f: 20 66 6f and %ah,0x6f(%esi)
52: 72 20 jb 74 <title+0x15>
54: 72 65 jb bb <title+0x5c>
56: 61 popa
57: 6c insb (%dx),%es:(%edi)
58: 20 6d 65 and %ch,0x65(%ebp)
5b: 6e outsb %ds:(%esi),(%dx)
5c: 2e 0a 00 or %cs:(%eax),%al
0000005f <title>:
5f: 4d dec %ebp
60: 61 popa
61: 64 65 20 62 79 fs and %ah,%fs:%gs:0x79(%edx)
66: 20 43 61 and %al,0x61(%ebx)
69: 70 74 jo df <title+0x80>
6b: 61 popa
6c: 69 6e 4f 62 76 69 6f imul $0x6f697662,0x4f(%esi),%ebp
73: 75 73 jne e8 <title+0x89>
75: 21 0a and %ecx,(%edx)
77: 00 b8 00 00 00 00 add %bh,0x0(%eax)
7d: c9 leave
7e: c3 ret
7f: 90 nop
这让我回到我的问题,我如何将程序集转换为我的主函数的整数操作码的常量数组?