无法理解汇编逻辑

Posted

技术标签:

【中文标题】无法理解汇编逻辑【英文标题】:Trouble understanding assembly logic 【发布时间】:2020-07-18 18:15:07 【问题描述】:

我对汇编比较陌生,我正在尝试理解以下汇编转储(这是我为了更熟悉汇编而尝试的常见“二进制炸弹”练习)。基本前提是您必须通过检查程序集和设置断点找到成功退出程序所需的正确输入,而不会“触发炸弹”(调用 explode_bomb 函数)。这是用于教授 GDB 调试和汇编语法的常见练习。

据我了解,该程序首先使用 scanf 检查字符串输入,并检查是否提供了 1 个参数。在设置断点并检查 eax 寄存器的值后,我可以看到我输入的输入值,所以似乎我应该寻找它来与其他东西进行比较。然后程序移动一些东西并将eax寄存器的值与二进制值0x52b = 1323进行比较。但是,我尝试使用这个值作为我的输入,但它不起作用所以我想知道我是否误解了背后的逻辑这个程序。

我将不胜感激任何帮助/建议!

已更新(我不确定这是否正确):

程序接受 1 个输入参数,存储在 eax 寄存器中。如果不是 1 个参数输入,则展开。 然后程序执行mov 0x1c(%esp),%eax,本质上执行eax = [esp + 0x1c](这不会覆盖程序的输入吗?) 然后程序执行lea (%eax,%eax,2),%eax,它本质上执行eax = eax + eax * 2 最后,程序执行cmp $0x52b,%eax,将eax 寄存器中的值与0x52b 进行比较。
0x08048bd0 <+0>:     sub    $0x2c,%esp
0x08048bd3 <+3>:     movl   $0x0,0x1c(%esp)
0x08048bdb <+11>:    lea    0x1c(%esp),%eax
0x08048bdf <+15>:    mov    %eax,0x8(%esp)
0x08048be3 <+19>:    movl   $0x804a644,0x4(%esp)
0x08048beb <+27>:    mov    0x30(%esp),%eax
0x08048bef <+31>:    mov    %eax,(%esp)
0x08048bf2 <+34>:    call   0x8048870 <__isoc99_sscanf@plt>
0x08048bf7 <+39>:    cmp    $0x1,%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    $0x52b,%eax
0x08048c0d <+61>:    je     0x8048c14 <phase_1+68>
0x08048c0f <+63>:    call   0x8049363 <explode_bomb>
0x08048c14 <+68>:    add    $0x2c,%esp
0x08048c17 <+71>:    ret  

【问题讨论】:

这个“二元炸弹”练习的目标是什么? @Ackdari 我更新了描述,它基本上是一个需要用户输入的二进制文件,如果这个输入是有效的,你就进入下一个级别,如果它无效,“炸弹”就会爆炸。目标是在不触发“炸弹”的情况下确定必要的输入是什么 eax 在位置&lt;+53&gt;&lt;+56&gt; 的值是多少?或者其他问题,它目前在什么时候爆炸&lt;+44&gt;&lt;+63&gt; 你传递给 scanf 内存中存储输入的地址(第 11 行)。 scanf 在 eax 中完成后,结果是解析了多少条目(应该是 1)。实际结果存储在那个内存位置 esp + 0x1c,这就是你从第 49 行得到它的地方。 scanf("%d", &int_var) - 在这种特定情况下,int_var 存储在位置 1c 的堆栈中。它可以是任何地址。例如,这个变量在栈上的位置取决于你是否在它之前定义了其他变量。 【参考方案1】:

在 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   $0x804a644,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

【讨论】:

以上是关于无法理解汇编逻辑的主要内容,如果未能解决你的问题,请参考以下文章

为啥这行得通?我无法理解这种交换的逻辑

汇编--逻辑指令

反汇编签名的dll [关闭]

汇编--指令系统 逻辑指令

无法理解这个字谜问题解决方案背后的逻辑[关闭]

汇编逻辑运算