C 解密x86汇编函数

C 解密x86汇编函数,c,assembly,x86,att,C,Assembly,X86,Att,我目前正在进行二元炸弹任务的第二阶段。我很难准确地理解某个函数在被调用时的功能。我已经坚持了好几天了 功能是: 0000000000400f2a <func2a>: 400f2a: 85 ff test %edi,%edi 400f2c: 74 1d je 400f4b <func2a+0x21> 400f2e: b9 cd cc cc cc mo

我目前正在进行二元炸弹任务的第二阶段。我很难准确地理解某个函数在被调用时的功能。我已经坚持了好几天了

功能是:

0000000000400f2a <func2a>:
  400f2a:   85 ff                   test   %edi,%edi
  400f2c:   74 1d                   je     400f4b <func2a+0x21>
  400f2e:   b9 cd cc cc cc          mov    $0xcccccccd,%ecx
  400f33:   89 f8                   mov    %edi,%eax
  400f35:   f7 e1                   mul    %ecx
  400f37:   c1 ea 03                shr    $0x3,%edx
  400f3a:   8d 04 92                lea    (%rdx,%rdx,4),%eax
  400f3d:   01 c0                   add    %eax,%eax
  400f3f:   29 c7                   sub    %eax,%edi
  400f41:   83 04 be 01             addl   $0x1,(%rsi,%rdi,4)
  400f45:   89 d7                   mov    %edx,%edi
  400f47:   85 d2                   test   %edx,%edx
  400f49:   75 e8                   jne    400f33 <func2a+0x9>
  400f4b:   f3 c3                   repz retq 
0000000000 400F2A:
400f2a:85 ff测试%edi,%edi
400f2c:74 1d je 400f4b
400f2e:b9 cd抄送mov$0xCCCD,%ecx
400f33:89 f8 mov%edi,%eax
400f35:f7 e1 mul%ecx
400f37:c1 ea 03 shr$0x3,%edx
400f3a:8d 04 92 lea(%rdx,%rdx,4),%eax
400f3d:01 c0添加%eax,%eax
400f3f:29 c7子%eax,%edi
400f41:83 04 be 01 addl$0x1,(%rsi,%rdi,4)
400f45:89 d7 mov%edx%edi
400f47:85 d2测试%edx,%edx
400f49:75 e8 jne 400f33
400f4b:f3 c3 repz retq
它在较大的函数“phase_2”中被调用:

0000000000 400F4D:
400f4d:53推送%rbx
400f4e:48 83 ec 60子$0x60,%rsp
400f52:48 c7 44 24 30 00 movq$0x0,0x30(%rsp)
400f59:00
400f5b:48 c7 44 24 38 00 movq$0x0,0x38(%rsp)
400f62:00
400f64:48 c7 44 24 40 00 movq$0x0,0x40(%rsp)
400f6b:00
400f6d:48 c7 44 24 48 00 movq$0x0,0x48(%rsp)
400f74:00
400f76:48 c7 44 24 50 00 movq$0x0,0x50(%rsp)
400f7d:00
400f7f:48 c7 04 24 00 movq$0x0,(%rsp)
400f86:00
400f87:48 c7 44 24 08 00 movq$0x0,0x8(%rsp)
400f8e:00
400f90:48 c7 44 24 10 00 movq$0x0,0x10(%rsp)
400f97:00
400f99:48 c7 44 24 18 00 movq$0x0,0x18(%rsp)
400fa0:00
400fa2:48 c7 44 24 20 00 movq$0x0,0x20(%rsp)
400fa9:00
400fab:48 8d 4c 24 58 lea 0x58(%rsp),%rcx
400fb0:48 8d 54 24 5c lea 0x5c(%rsp),%rdx
400fb5:be 9e 26 40 00 mov$0x40269e,%esi
400fba:b8 00 mov$0x0,%eax
400fbf:e8 6c fc ff ff呼叫400c30
400fc4:83 f8 02 cmp$0x2,%eax
400fc7:74 05 je 400fce
400fc9:e8 c1 06 00 00 callq 40168f
400fce:83 7c 24 5c 64 cmpl$0x64,0x5c(%rsp)
400fd3:76 07 jbe 400fdc
400fd5:83 7c 24 58 64 cmpl$0x64,0x58(%rsp)
400fda:77 05 ja 400fe1
400fdc:e8 ae 06 00 00 callq 40168f
400fe1:48 8d 74 24 30 lea 0x30(%rsp),%rsi
400fe6:8b 7c 24 5c mov 0x5c(%rsp),%edi
400fea:e8 3b ff ff callq 400f2a
400fef:4889E6MOV%rsp%rsi
400ff2:8b 7c 24 58 mov 0x58(%rsp),%edi
400ff6:e8 2f ff ff callq 400f2a
400ffb:bb 00 mov$0x0,%ebx
401000:8b 04 1c mov(%rsp,%rbx,1),%eax
401003:39 44 1c 30 cmp%eax,0x30(%rsp,%rbx,1)
401007:74 05 je 40100e
401009:e8 81 06 00 callq 40168f
40100e:48 83 c3 04添加$0x4,%rbx
401012:48 83 fb 28 cmp$0x28,%rbx
401016:75 e8 jne 401000
401018:48 83 c4 60添加$0x60,%rsp
40101c:50亿波普%rbx
40101d:c3 retq
我完全理解阶段2在做什么,我只是不理解func2a在做什么,以及它如何影响0x30(%rsp)处的值,等等。因此,我总是在0x401003处找到比较语句,炸弹最终在那里爆炸

我的问题是我不理解输入(相位解决方案)如何通过func2a影响0x30(%rsp)处的值

  400f2a:   85 ff                   test   %edi,%edi
  400f2c:   74 1d                   je     400f4b <func2a+0x21>
这是一个经典的优化技巧;它是一个整数算术等价物,等于除以逆(参见);实际上,这里的意思与说edx=edi/10是一样的

  400f3a:   8d 04 92                lea    (%rdx,%rdx,4),%eax
  400f3d:   01 c0                   add    %eax,%eax
在这里,它利用
lea
执行算术(在英特尔语法中更清晰,它是
leaeax,[rdx+rdx*4]
=>
eax=edx*5
),然后将结果与自身相加。这一切归结为eax=edx*10

  400f3f:   29 c7                   sub    %eax,%edi
然后,将其减去回
edi

void func2a(unsigned edi, int rsi[]) {
    if(edi==0) return;
label1:
    edx=edi/10;
    edi%=10;
    rsi[edi]++;
}

因此,总而言之,这是一种复杂(但快速)的方法来计算
edi
的最后一个十进制数字;到目前为止,我们所拥有的是:

void func2a(unsigned edi) {
    if(edi==0) return;
label1:
    edx=edi/10;
    edi%=10;
    // ...
}
label1:
存在,因为
400f33
是稍后的跳转目标)


继续:

  400f41:   83 04 be 01             addl   $0x1,(%rsi,%rdi,4)
同样,在英特尔语法中,这对我来说更清楚了-
添加dword[rsi+rdi*4],字节+0x1
。它是32位
int
数组的规则增量(
rdi
乘以4);因此,我们可以想象,
rsi
指向一个整数数组,用刚刚计算的最后一位
edi
索引

void func2a(unsigned edi, int rsi[]) {
    if(edi==0) return;
label1:
    edx=edi/10;
    edi%=10;
    rsi[edi]++;
}
然后:

返回(使用)


因此,通过使用
while
循环重写跳转,并给出一些有意义的名称

// number is edi, digits_count is rsi, as per regular
// x64 SystemV calling convention
void count_digits(unsigned number, int digits_count[]) {
    while(number) {
        digits_count[number%10]++;
        number/=10;
    }
}
也就是说,这是一个函数,给定一个整数,通过增加
digits\u count
数组中相应的存储桶来计算单个十进制数字的出现次数



有趣的事实:如果我们将上面的C代码交给
gcc
(几乎是
-O1
上的任何最新版本)。

“如果我们将上面的C代码交给gcc,我们将获得您提供的组件。”->完美的逆向工程。回答得好!
  400f45:   89 d7                   mov    %edx,%edi
  400f47:   85 d2                   test   %edx,%edx
  400f49:   75 e8                   jne    400f33 <func2a+0x9>
  400f4b:   f3 c3                   repz retq 
// number is edi, digits_count is rsi, as per regular
// x64 SystemV calling convention
void count_digits(unsigned number, int digits_count[]) {
    while(number) {
        digits_count[number%10]++;
        number/=10;
    }
}