我有一个非常相似的问题:Binary Bomb - Phase 4但它仍然不同,我不完全确定该怎么做。
这是我的phase_4代码:
public static function getTickets($conn){
$sql = "select tickets.*,customers.* from tickets,customers where
(tickets.ticket_customer_id = customers.customer_id) order by tickets.ticket_open_date desc ";
$st = $conn->query($sql);
$list = array();
while($row=$st->fetch(PDO::FETCH_ASSOC)) {
$list[] = New Tickets($row);
$columnNames = array_keys($row);
}
//total rows of customer
$totalRows = count($list);
$columnCount = count($columnNames);
//pass the values to page
return (array("results"=>$list ,"totalRows"=>$totalRows,"columnCount"=>$columnCount));
}
这是func_4代码:
08048d3e <phase_4>:
8048d3e: 83 ec 2c sub $0x2c,%esp
8048d41: 8d 44 24 18 lea 0x18(%esp),%eax
8048d45: 89 44 24 0c mov %eax,0xc(%esp)
8048d49: 8d 44 24 1c lea 0x1c(%esp),%eax
8048d4d: 89 44 24 08 mov %eax,0x8(%esp)
8048d51: c7 44 24 04 75 a7 04 movl $0x804a775,0x4(%esp)
8048d58: 08
8048d59: 8b 44 24 30 mov 0x30(%esp),%eax
8048d5d: 89 04 24 mov %eax,(%esp)
8048d60: e8 6b fb ff ff call 80488d0 <__isoc99_sscanf@plt>
8048d65: 83 f8 02 cmp $0x2,%eax //making sure I have 2 inputs
8048d68: 75 0e jne 8048d78 <phase_4+0x3a> //if not explodes bomb
8048d6a: 8b 44 24 18 mov 0x18(%esp),%eax
8048d6e: 83 f8 01 cmp $0x1,%eax //has to be greater than 1
8048d71: 7e 05 jle 8048d78 <phase_4+0x3a> //otherwise jumps to bomb
8048d73: 83 f8 04 cmp $0x4,%eax
8048d76: 7e 05 jle 8048d7d <phase_4+0x3f> //has to be less than 4 or jumps to bomb
8048d78: e8 af 05 00 00 call 804932c <explode_bomb>
8048d7d: 8b 44 24 18 mov 0x18(%esp),%eax
8048d81: 89 44 24 04 mov %eax,0x4(%esp)
8048d85: c7 04 24 09 00 00 00 movl $0x9,(%esp)
8048d8c: e8 50 ff ff ff call 8048ce1 <func4> //calls function 4
8048d91: 3b 44 24 1c cmp 0x1c(%esp),%eax
8048d95: 74 05 je 8048d9c <phase_4+0x5e> //compares two values and explodes bomb if not equal
8048d97: e8 90 05 00 00 call 804932c <explode_bomb>
8048d9c: 83 c4 2c add $0x2c,%esp
8048d9f: 90 nop
8048da0: c3 ret
我已经检查过以确保输入必须是两位小数,我还可以看到最后两个数字相互比较(8048d97,0x1c(%esp)和%eax)。在phase_4的开头,我认为代码也表明第一个数字必须在1到4之间,而在第4阶段结束时,数字已被修改,它必须等于第二个数字。如果我错了,请纠正我。
我只是不确定func_4正在做什么,以及如何确定输入应该是什么。我认为它可能是二进制搜索,但不确定如何检查它与第一个输入的对应关系。任何帮助将不胜感激!
答案 0 :(得分:0)
func_4正在做什么,以及如何确定输入应该是什么。
8048d81: 89 44 24 04 mov %eax,0x4(%esp)
; input value loaded to [esp+4] -> [esp+0x24] inside func4
8048d85: c7 04 24 09 00 00 00 movl $0x9,(%esp)
; 9 stored to [esp+0] -> [esp+0x20] inside func4
8048d8c: e8 50 ff ff ff call 8048ce1 <func4>
; something calculated
; then the result is compared with other input value, they should be equal
我不确定,哪个输入是哪个(你知道sscanf和你的ABI的格式字符串,所以你可以更好地说明,存储在[esp + 0x18]中并且测试为2的值,在计算中使用了3或4,只是比较了存储在[esp + 0x1c]中的那个。我猜想计算的输入是秒(对于sscanf在+ 0x0c,另一个在+ 0x08)?所以密码是& #34; <func4(9,2-4)> <2-4>
&#34;
由于func4是干净的asm递归代码,你可以为所有三个可能的输入运行它,看看它产生了什么结果(在调试器中,踩过指令,所以你设法捕获一些参数导致无限循环或一些其他的肮脏,加上你会知道它是如何工作的。)
然后找出哪个输入。
嘿,这就是装配工作的方式。您很少查看指令流,并快速浏览它们中的算法。更常见的是,你需要通过指令彻底模拟头部指令中的CPU状态,注意每个细节(比如通过指令改变标志,看起来只用于设置值,然后稍后指示保留标志用于条件通过保持计算值的某些时间线,通常可以猜测实现的算法。不确定func_4正在做什么
或者如果不是算法,那么至少要知道计算出什么值。
我再次检查了代码,看起来像Fibonnaci主题的变体,如func4(0,x) = 0
,func4(1,x) = x
和func4(y, x)
= (只是快速猜测,太懒了)验证我做对了) x + func4(y-1, x) + func4(y-2, x)
。
编辑:我现在确定公式不正确,至少缺少一个常量(但可能更糟糕)。
所以我想知道,你是否懒得费心去模拟CPU并获得正确的结果,或者你对某些特定指令有问题,它究竟做了什么(即你懒得阅读指令参考指南)?所以它归结为&#34;你是懒惰还是懒惰?&#34;因为我绝对都是,所以这是我对你的问题的回答。 :)
如果您不了解某些指示的某些特定细节,请询问。
编辑评论:
&#34; //必须小于4或跳到炸弹&#34;
不,它是jle
,&#34;跳过的签名少于/等于&#34;,所以正确的评论是&#34;必须少于等于4&#34;这对值[TYPE_MIN,4]有效。
对于&#34;少于4&#34;你需要使用jl
=&#34;跳过签名更少&#34;。
对于&#34;少于4&#34;那里没有签名jb
=&#34;跳到&#34;以下,它涵盖了值[0,3]。 jbe
涵盖[0,4]值。
如果要检查Jcc description,您将看到这些条件跳转仅基于标志寄存器中的少数标志,仅此而已(jcxz/jecxz
除外,它比较cx
寄存器并且不会#39; t触摸旗帜。)
此外,您可能会注意到有几个别名,因此您可以在代码中写入符合您目的的代码。例如jz
和je
是相同的指令,第一个别名代表&#34;当零(标志)&#34;时跳转,另一个是#34;等于&#34; 。因此,通读它并习惯这些缩写,它将使拆卸的阅读更容易一些。
//调用函数4
这无用的评论,从指令本身来看是显而易见的。你会添加例如参数(9,input_2),这对读者来说会更有益。
下一个&#34;比较&#34;评论具有类似无用的性质。两个数字是什么?如果你已经对它们进行了追踪,那么你应该把这个结果写成注释,这样就像&#34;比较func4的结果和input_1&#34;。
我将尝试向您展示func4:
的示例 8048ce1 <func4>:
; allocates 0x1c bytes on stack for local variables
; (so return address is at [esp+0x1c] now, was at [esp])
8048ce1: 83 ec 1c sub $0x1c,%esp
; stores current ebx, esi and edi in [esp+0x10 / 0x14 / 0x18]
8048ce4: 89 5c 24 10 mov %ebx,0x10(%esp)
8048ce8: 89 74 24 14 mov %esi,0x14(%esp)
8048cec: 89 7c 24 18 mov %edi,0x18(%esp)
; esi = [esp+0x20] = first argument of func4(arg1, arg2)
8048cf0: 8b 74 24 20 mov 0x20(%esp),%esi
; ebx = [esp+0x24] = second argument of func4(arg1, arg2)
8048cf4: 8b 5c 24 24 mov 0x24(%esp),%ebx
; when esi(arg1) <= 0, jump to ExitWith0
8048cf8: 85 f6 test %esi,%esi
8048cfa: 7e 2b jle 8048d27 ExitWith0
; when esi(arg1) == 1, jump to ExitWithValueFromEbx
8048cfc: 83 fe 01 cmp $0x1,%esi
8048cff: 74 2b je 8048d2c ExitWithValueFromEbx
; store arg2 in [esp+4]
8048d01: 89 5c 24 04 mov %ebx,0x4(%esp)
; store (arg1-1) in [esp] (preparing args for recursive call)
8048d05: 8d 46 ff lea -0x1(%esi),%eax
8048d08: 89 04 24 mov %eax,(%esp)
; recursion: eax = func4(arg1-1, arg2) ; ebx/esi/edi preserved
8048d0b: e8 d1 ff ff ff call 8048ce1 <func4>
; edi = eax (result) + ebx*1 (arg2)
8048d10: 8d 3c 18 lea (%eax,%ebx,1),%edi
; [esp+4] is set to arg2 again
; (it's still there, but this asm looks like debug level of C, not very efficient)
8048d13: 89 5c 24 04 mov %ebx,0x4(%esp)
; esi -= 2 (no more original arg1 in esi), and set [esp+0]
8048d17: 83 ee 02 sub $0x2,%esi
8048d1a: 89 34 24 mov %esi,(%esp)
; second recursive call: func4(arg1-2, arg2)
8048d1d: e8 bf ff ff ff call 8048ce1 <func4>
; ebx = edi + eax*1 ; edi was arg2 + f4(arg1-1, arg2)
8048d22: 8d 1c 07 lea (%edi,%eax,1),%ebx
; so ebx = arg2 + f4(arg1-1, arg2) + f4(arg1-2, arg2), return that value
8048d25: eb 05 jmp 8048d2c ExitWithValueFromEbx
ExitWith0:
8048d27: bb 00 00 00 00 mov $0x0,%ebx
ExitWithValueFromEbx:
8048d2c: 89 d8 mov %ebx,%eax
; restore values of ebx/esi/edi (return value is in eax)
8048d2e: 8b 5c 24 10 mov 0x10(%esp),%ebx
8048d32: 8b 74 24 14 mov 0x14(%esp),%esi
8048d36: 8b 7c 24 18 mov 0x18(%esp),%edi
; restore esp value, so [esp] is return address, and return
8048d3a: 83 c4 1c add $0x1c,%esp
8048d3d: c3 ret
所以我在答案中确实猜到了,那些,1)
在lea中迷惑了我,我不熟悉AT&amp; T语法,所以在一个较弱的时刻我认为&#39; s + 1到结果,但它是* 1到索引寄存器(我习惯于英特尔语法,它看起来像lea ebx,[edi+eax]
)。
但正如您所看到的,一旦您开始记下笔记,并专注于单一指令,我确实设法在这次正确解读。
目前,确保理解每条指令对您来说非常重要,我指的是每一个细节,例如lea
如何工作以及为什么它不读取内存值,即使参数是(...)
,什么是所有可能的寻址模式(如果你想做f(a,b)= 1 + b + f(a-1,b)+ f,它会是什么样子( a-2,b)?尝试找到一个,只需要修改一个lea
(这两个中的任何一个))。
我不确定你有什么文献,因为我使用了英特尔语法的一切(我认为AT&amp; T语法对C编译器有好处,但对人类来说并不是那么多......但总体而言#39 ;不是那么糟糕,如果你已经知道另一个,那么大多是烦人的,如果你只知道AT&amp; T,那可能就行了。)
在最坏的情况下问一下,虽然有关说明目的的问题是&#34;省力&#34;,因为所有x86手册都是免费提供的,但是如果你不确定某些措辞的真正意义,并且运行这样的指令很少调试器中的时间没有帮助,你必须要问。只需添加您的想法以及令您困惑的词语。