难以理解汇编逻辑
Trouble understanding assembly logic
我对汇编比较陌生,正在尝试理解以下汇编程序转储(这是来自我正在尝试的常见 'binary bomb' 练习,以便更熟悉汇编)。基本前提是您必须通过检查程序集和设置断点来找到在没有 "triggering the bomb"(调用 explode_bomb 函数)的情况下成功退出程序所需的正确输入。这是用于教授 GDB 调试和汇编语法的常见练习。
据我了解,该程序首先使用 scanf 检查字符串输入并检查是否提供了 1 个参数。在设置断点并检查 eax 寄存器的值后,我能够看到我输入的输入值,所以我似乎应该寻找它与其他东西进行比较。然后程序移动一些东西并将 eax 寄存器的值与二进制值 0x52b = 1323 进行比较。但是,我尝试使用这个值作为我的输入但它不起作用所以我想知道我是否误解了背后的逻辑这个程序。
我将不胜感激 help/advise!
已更新(不知是否正确):
- 程序接受1个输入参数,存储在eax寄存器中。如果不是 1 个参数输入则爆炸。
- 程序然后执行
mov 0x1c(%esp),%eax
,实际上执行 eax = [esp + 0x1c]
(这不会覆盖程序的输入吗?)
- 程序然后执行
lea (%eax,%eax,2),%eax
本质上执行 eax = eax + eax * 2
- 最后,程序执行
cmp [=15=]x52b,%eax
,将 eax
寄存器中的值与 0x52b
. 进行比较
0x08048bd0 <+0>: sub [=10=]x2c,%esp
0x08048bd3 <+3>: movl [=10=]x0,0x1c(%esp)
0x08048bdb <+11>: lea 0x1c(%esp),%eax
0x08048bdf <+15>: mov %eax,0x8(%esp)
0x08048be3 <+19>: movl [=10=]x804a644,0x4(%esp)
0x08048beb <+27>: mov 0x30(%esp),%eax
0x08048bef <+31>: mov %eax,(%esp)
0x08048bf2 <+34>: call 0x8048870 <__isoc99_sscanf@plt>
0x08048bf7 <+39>: cmp [=10=]x1,%eax
0x08048bfa <+42>: je 0x8048c01 <phase_1+49>
0x08048bfc <+44>: call 0x8049363 <explode_bomb>
0x08048c01 <+49>: mov 0x1c(%esp),%eax
0x08048c05 <+53>: lea (%eax,%eax,2),%eax
0x08048c08 <+56>: cmp [=10=]x52b,%eax
0x08048c0d <+61>: je 0x8048c14 <phase_1+68>
0x08048c0f <+63>: call 0x8049363 <explode_bomb>
0x08048c14 <+68>: add [=10=]x2c,%esp
0x08048c17 <+71>: ret
在 x86 32 位中,参数根据 IA32 cdecl 调用约定在堆栈上传递(有关详细信息,请参阅 this wiki page)。
您的 phase_1
函数正在调用 sscanf()
,在此处传递参数:
0x08048bdb <+11>: lea 0x1c(%esp),%eax
0x08048bdf <+15>: mov %eax,0x8(%esp)
0x08048be3 <+19>: movl [=10=]x804a644,0x4(%esp)
0x08048beb <+27>: mov 0x30(%esp),%eax
0x08048bef <+31>: mov %eax,(%esp)
简而言之,就是:
sscanf(esp + 0x30, 0x804a644, esp + 0x1c);
应该是这样的:
int var_on_stack;
sscanf(user_input, "%d", &var_on_stack);
// user_input starts at esp + 0x30
// &var_on_stack == esp + 0x1c
第一个参数 (user_input
) 可能作为参数传递给 phase_1
函数,它可能包含之前读取的数据。
值 0x804a644
是传递给 scanf()
的格式字符串的地址,我假设它类似于 "%d"
,因为此后该值被视为整数。您可以使用 x/s 0x804a644
检查地址 0x804a644
处的内容,以准确查看格式字符串的内容(并了解正在读取的变量的类型)。
之后,这两条指令:
0x08048c01 <+49>: mov 0x1c(%esp),%eax
0x08048c05 <+53>: lea (%eax,%eax,2),%eax
从栈中取出扫描值放入eax
,然后乘以3
(即lea
最后做eax = eax*2 + eax
)。
完成后,将值与 0x52b
进行比较。因此需要输入0x52b/3
,也就是1323/3
,也就是441
.
我对汇编比较陌生,正在尝试理解以下汇编程序转储(这是来自我正在尝试的常见 'binary bomb' 练习,以便更熟悉汇编)。基本前提是您必须通过检查程序集和设置断点来找到在没有 "triggering the bomb"(调用 explode_bomb 函数)的情况下成功退出程序所需的正确输入。这是用于教授 GDB 调试和汇编语法的常见练习。
据我了解,该程序首先使用 scanf 检查字符串输入并检查是否提供了 1 个参数。在设置断点并检查 eax 寄存器的值后,我能够看到我输入的输入值,所以我似乎应该寻找它与其他东西进行比较。然后程序移动一些东西并将 eax 寄存器的值与二进制值 0x52b = 1323 进行比较。但是,我尝试使用这个值作为我的输入但它不起作用所以我想知道我是否误解了背后的逻辑这个程序。
我将不胜感激 help/advise!
已更新(不知是否正确):
- 程序接受1个输入参数,存储在eax寄存器中。如果不是 1 个参数输入则爆炸。
- 程序然后执行
mov 0x1c(%esp),%eax
,实际上执行eax = [esp + 0x1c]
(这不会覆盖程序的输入吗?) - 程序然后执行
lea (%eax,%eax,2),%eax
本质上执行eax = eax + eax * 2
- 最后,程序执行
cmp [=15=]x52b,%eax
,将eax
寄存器中的值与0x52b
. 进行比较
0x08048bd0 <+0>: sub [=10=]x2c,%esp
0x08048bd3 <+3>: movl [=10=]x0,0x1c(%esp)
0x08048bdb <+11>: lea 0x1c(%esp),%eax
0x08048bdf <+15>: mov %eax,0x8(%esp)
0x08048be3 <+19>: movl [=10=]x804a644,0x4(%esp)
0x08048beb <+27>: mov 0x30(%esp),%eax
0x08048bef <+31>: mov %eax,(%esp)
0x08048bf2 <+34>: call 0x8048870 <__isoc99_sscanf@plt>
0x08048bf7 <+39>: cmp [=10=]x1,%eax
0x08048bfa <+42>: je 0x8048c01 <phase_1+49>
0x08048bfc <+44>: call 0x8049363 <explode_bomb>
0x08048c01 <+49>: mov 0x1c(%esp),%eax
0x08048c05 <+53>: lea (%eax,%eax,2),%eax
0x08048c08 <+56>: cmp [=10=]x52b,%eax
0x08048c0d <+61>: je 0x8048c14 <phase_1+68>
0x08048c0f <+63>: call 0x8049363 <explode_bomb>
0x08048c14 <+68>: add [=10=]x2c,%esp
0x08048c17 <+71>: ret
在 x86 32 位中,参数根据 IA32 cdecl 调用约定在堆栈上传递(有关详细信息,请参阅 this wiki page)。
您的 phase_1
函数正在调用 sscanf()
,在此处传递参数:
0x08048bdb <+11>: lea 0x1c(%esp),%eax
0x08048bdf <+15>: mov %eax,0x8(%esp)
0x08048be3 <+19>: movl [=10=]x804a644,0x4(%esp)
0x08048beb <+27>: mov 0x30(%esp),%eax
0x08048bef <+31>: mov %eax,(%esp)
简而言之,就是:
sscanf(esp + 0x30, 0x804a644, esp + 0x1c);
应该是这样的:
int var_on_stack;
sscanf(user_input, "%d", &var_on_stack);
// user_input starts at esp + 0x30
// &var_on_stack == esp + 0x1c
第一个参数 (user_input
) 可能作为参数传递给 phase_1
函数,它可能包含之前读取的数据。
值 0x804a644
是传递给 scanf()
的格式字符串的地址,我假设它类似于 "%d"
,因为此后该值被视为整数。您可以使用 x/s 0x804a644
检查地址 0x804a644
处的内容,以准确查看格式字符串的内容(并了解正在读取的变量的类型)。
之后,这两条指令:
0x08048c01 <+49>: mov 0x1c(%esp),%eax
0x08048c05 <+53>: lea (%eax,%eax,2),%eax
从栈中取出扫描值放入eax
,然后乘以3
(即lea
最后做eax = eax*2 + eax
)。
完成后,将值与 0x52b
进行比较。因此需要输入0x52b/3
,也就是1323/3
,也就是441
.