首页
社区
课程
招聘
[原创]#30天写作挑战#反汇编代码还原之优化方式
发表于: 2020-9-1 22:44 15991

[原创]#30天写作挑战#反汇编代码还原之优化方式

2020-9-1 22:44
15991

在我们学习反汇编的时候.很多人都以为反汇编很难. 其实不然. 学什么都是有技巧的.

而想要锻炼我们的反汇编能力. 第一就是要进行多练. 第二就是熟悉底层原理. 第三就是熟悉套路.

往后几篇 会把C与C++的反汇编形式体现出来. 如果写的不对的话请批评指正.

​ 汇编中的加法 减法 乘法 除法 取模 等等 都是有优化方式.以及有套路的.

​ 优化方式分为以下几种

那么着重介绍一下上面优化方式所代表的意思.

优化的前提是在 Release下切开启O2选项优化速度的前提 Debug版本也会优化但是更多的是方便程序员调试.所以在不影响调试的前提下才会进行优化.

有以下例子:

所谓常量折叠就是 在编译前 所遇到的常量.是可以进行计算的.那么就会优化为一个常量值

例如上面的 7 + 8 不会产生add指令 而是在程序编译后直接成为 15(0xF)

VC6.0VS2019分别编译 为什么要两个编译器. 目的就是让大家知道.这个套路不管是几十年前的6.0还是现如今的Vs2019 都是一样的. 可能会有些稍许不同.但是绝不影响你的逆向.以及反汇编.而恰巧这才是真正的核心所在.包括gcc编译也是一样.

Vc6.0 保留核心

可以看到 7+8在反汇编的形势下直接变为了 0xF. 也就是10进制的15

Vs2019

可以看到唯一不同的就是高版本 IDA没有识别出sig库.所以调用的都成了 sub_401010 而低版本函数已经认出来了.

还有就是文件体积变大了. vc6.0 编译出来28kb 2019编译出来98kb. 你品.

上面例子足以说明什么是常量折叠 含义就是常量会在编译器给你计算出来

常量传播也叫做常量扩散 指的就是 变量在写入或者读取的时候没有传递内存地址(&)也没有传指针或者引用来修改值的时候就会发生常量传播

大白话讲就是 你没有修改我变量的代码.那么这个变量我就可以认为是常量了.

以上面高级代码为例子

那么进行常量传播之后. n因为没有对其修改.也没有对其进行传地址的操作. 所以编译器就会把它变为常量了.

那么上面的代码就会产生如下代码

而看到这里想必大家应该明白了. 0 + 6 又符合常量折叠. 所以代码继续变化

以上面汇编为例子

想必大家知道这里为啥是 push 6 了. 这里进行了两次优化 一次是常量传播,一次是常量折叠

变量去除指的就是你程序中定义了变量但是没有对其进行修改. 然后进行常量传播,常量折叠一步一步给优化掉

还是以高级代码为例子

程序首先发现 n m 两个变量相加. 但是看了一下上面. 发现没有对其进行修改.所以代码就会变为如下

而0+1符合常量折叠.所以最终代码就变为了.

对应反汇编

归并优化,如果可以一起优化那么我就一起优化.

我们知道 printf 属于C调用约定. 所以需要外平栈 而且他是可变参.通过你push参数个数的不同.外平栈的大小也会相应改变

比如:

但是我们在上面的汇编代码中.并没有看到 add esp,8 而是直接看到了 add esp,0x18

原因是什么. 在你调用printf的时候.而下面你又调用了相同的几个 printf ,printf 都是C调用约定.

所以我就一起给你平了

所以代码就有如下

一个参数是4个字节. 所以累计总共push了6个参数. 4 * 6 = 24个字节.所以平栈也需要24个字节

24恰巧是 十六进制的 0x18

Cpu流水线优化其实说白了就是打乱指令执行顺序,而不影响原有功能. 这个在我们反汇编的时候需要注意.正常的汇编代码都是平平整整顺顺序序 让人一眼看的很舒服,而且反汇编出高级代码也很快.

这里以简单的汇编为例子 因为我要写很多代码才会遇到流水线优化.这里我模拟一下

正常的汇编代码指令顺序

打乱的流水线

汇编代码就很简单.

我们着重看一下打乱的汇编.

在没打乱之前代码平平整整.打乱之后发现很多汇编进行了穿插

比如

在Cpu执行 mov eax,1的时候.可以直接执行 xor ecx,ecx 这样的好处是下一行汇编不依赖于上一行汇编.

之前的指令是下一行指令依赖于上一行指令. 那么Cpu 如果在执行第二行的时候发现你依赖于上一行汇编.那么就会等待.

第一行执行了 mov eax,1 那么第二行又使用了eax. 那么第二行执行的时候就要等待第一行.

而打断的好处就是 我执行第一行的时候也可以执行第二行而且不会影响你的结果. 也可以提升速度

流水线优化需要你细品.

当你品完之后再看下打乱的汇编

是不是发现很顺眼了. 那么当你还原的时候完全可以按照自己的意愿来恢复汇编进行还原

是不是就很简单了.

数学变换优化: 如果操作的数是无意义的.那么就会进行优化.

那么以上高级代码直接进行优化.优化为

不可达分支则是分支永远都不会走.那么也不会产生汇编代码.也没有存在的意义

上面已经知道a就是个常量.值就是10.那么会走if块. 而 else永远不会走.那么就会将else优化掉. 当然实际情况中代码肯定很多.不会像我一样简单的写一个 a = 10 去判断.

所谓代码外提一般是在循环的时候进行优化.循环体内部没有产生修改此变量的代码.就会进行优化

循环体内部并没有操作y/3. 所以这个值都会放到外面执行
则会优化为

而t变量很可能也会经过上面的几种优化变为了寄存器变量

​ 代码混淆与优化是对立的.所以学习下优化也方便我们更好的"人肉"优化混淆代码

去掉优化的方式说一下

上面所说.都是编译器已经识别到了你的程序没有传地址传指针等. 所以我们想办法就不让他优化.

简单的函数如果你什么也不做也会给你优化掉的.

我们使用了很多scanf 以及printf 并对其变量取地址 那么编译器就不知道我们会不会修改变量的值了.

那么就不会给我们优化了.此时查看汇编代码就能看到真实的最小限度的优化代码了.

上面的几种优化方式,虽然很简单.但是我们也必须要掌握以及了解的. 因为后面的反汇编 代码还原 会有更多的优化. 而那些优化在配合 上面所说的优化就会让你感觉很难. 或者不知道汇编为什么那样做. 而你了解了这些 在单独看各自的优化就会明白.也会豁然开朗.

这些在我博客上已经写过.这里发出来也是为了让新会员重新了解一下反汇编. 高手能复习. 新人能学习.

CPP代码很简单.本次不提交了

 
 
 
 
int n = 0;
int m = 1;
printf("%d",7 + 8);
printf("%d",n + 6);
printf("%d",n + m);
int n = 0;
int m = 1;
printf("%d",7 + 8);
printf("%d",n + 6);
printf("%d",n + m);
 
 
 
.text:00401000                 push    0Fh
.text:00401002                 push    offset aD       ; "%d"
.text:00401007                 call    _printf
.text:0040100C                 push    6
.text:0040100E                 push    offset aD       ; "%d"
.text:00401013                 call    _printf
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
.text:00401024                 add     esp, 18h
.text:00401000                 push    0Fh
.text:00401002                 push    offset aD       ; "%d"
.text:00401007                 call    _printf
.text:0040100C                 push    6
.text:0040100E                 push    offset aD       ; "%d"
.text:00401013                 call    _printf
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
.text:00401024                 add     esp, 18h
 
.text:00401040 sub_401040      proc near               ; CODE XREF: start-8D↓p
.text:00401040                 push    0Fh
.text:00401042                 push    offset unk_417A8C
.text:00401047                 call    sub_401010
.text:0040104C                 push    6
.text:0040104E                 push    offset unk_417A8C
.text:00401053                 call    sub_401010
.text:00401058                 push    1
.text:0040105A                 push    offset unk_417A8C
.text:0040105F                 call    sub_401010
.text:00401064                 add     esp, 18h
.text:00401067                 xor     eax, eax
.text:00401069                 retn
.text:00401069 sub_401040      endp
.text:00401040 sub_401040      proc near               ; CODE XREF: start-8D↓p
.text:00401040                 push    0Fh
.text:00401042                 push    offset unk_417A8C
.text:00401047                 call    sub_401010
.text:0040104C                 push    6
.text:0040104E                 push    offset unk_417A8C
.text:00401053                 call    sub_401010
.text:00401058                 push    1
.text:0040105A                 push    offset unk_417A8C
.text:0040105F                 call    sub_401010
.text:00401064                 add     esp, 18h
.text:00401067                 xor     eax, eax
.text:00401069                 retn
.text:00401069 sub_401040      endp
 
 
 
 
int n = 0;
printf("%d",n + 6);
int n = 0;
printf("%d",n + 6);
 
int n = 0;
printf("%d",0 + 6);
int n = 0;
printf("%d",0 + 6);
int n = 0;
printf("%d",6);
int n = 0;
printf("%d",6);
.text:0040100C                 push    6
.text:0040100E                 push    offset aD       ; "%d"
.text:00401013                 call    _printf
.text:0040100C                 push    6
.text:0040100E                 push    offset aD       ; "%d"
.text:00401013                 call    _printf
 
int n = 0;
int m = 1;
printf("%d",n + m);
int n = 0;
int m = 1;
printf("%d",n + m);
printf("%d",0 + 1);
printf("%d",0 + 1);
printf("%d",1);
printf("%d",1);
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
 
 
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
                               add esp,8
.text:00401018                 push    1
.text:0040101A                 push    offset aD       ; "%d"
.text:0040101F                 call    _printf
                               add esp,8
 
 
 
.text:00401040 sub_401040      proc near               ; CODE XREF: start-8D↓p
.text:00401040                 push    0Fh
.text:00401042                 push    offset unk_417A8C
.text:00401047                 call    sub_401010
.text:0040104C                 push    6
.text:0040104E                 push    offset unk_417A8C
.text:00401053                 call    sub_401010
.text:00401058                 push    1
.text:0040105A                 push    offset unk_417A8C
.text:0040105F                 call    sub_401010
.text:00401064                 add     esp, 18h
.text:00401067                 xor     eax, eax
.text:00401069                 retn
.text:00401069 sub_401040      endp
.text:00401040 sub_401040      proc near               ; CODE XREF: start-8D↓p
.text:00401040                 push    0Fh
.text:00401042                 push    offset unk_417A8C

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2020-9-21 11:58 被TkBinary编辑 ,原因: 流水线优化位置,操作数手写有误.修改了
收藏
免费 19
支持
分享
打赏 + 3.00雪花
打赏次数 3 雪花 + 3.00
 
赞赏  Passdtab   +1.00 2020/09/03 上天入地,无所不能。
赞赏  Editor   +1.00 2020/09/02 精品文章~
赞赏  Ack麦子   +1.00 2020/09/02 感谢分享~
最新回复 (23)
雪    币: 23080
活跃值: (3432)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
2
666
2020-9-2 09:43
0
雪    币: 26185
活跃值: (63317)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
3
感谢分享!
2020-9-2 09:50
0
雪    币: 41
活跃值: (828)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
豁然开朗
2020-9-2 10:11
0
雪    币: 888
活跃值: (9861)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
5
金奔腾 豁然开朗
干就完了
2020-9-2 10:12
0
雪    币: 888
活跃值: (9861)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
6
2020-9-2 10:12
0
雪    币: 498
活跃值: (251)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
学习了
2020-9-2 10:14
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
666
2020-9-2 10:58
0
雪    币: 136
活跃值: (432)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
写的不错。
2020-9-2 11:30
0
雪    币: 203
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
nice
2020-9-2 11:36
0
雪    币: 446
活跃值: (595)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学习学习
2020-9-2 13:55
0
雪    币: 8447
活跃值: (5041)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
12
支持,加一个inline优化吧,这个也属于比较基础的
2020-9-2 14:04
0
雪    币: 888
活跃值: (9861)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
13
alphc 支持,加一个inline优化吧,这个也属于比较基础的
好的我一会看看.这个应该属于C++的.等后面还会继续出C以及C++的各种优化我顺便看看. 谢谢提醒.
2020-9-2 14:08
0
雪    币: 751
活跃值: (3833)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
合适入门,支持下!
2020-9-2 14:27
0
雪    币: 20
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
支持哦!
2020-9-2 15:57
0
雪    币: 1
活跃值: (207)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
好文章好老师
2020-9-3 07:14
0
雪    币: 1768
活跃值: (239)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
膜拜大佬,顶一个
2020-9-3 14:08
0
雪    币: 2276
活跃值: (2396)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
已学习。
2020-9-4 09:19
0
雪    币: 5596
活跃值: (2173)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
跟着楼主30天学习
2020-9-4 09:36
0
雪    币: 446
活跃值: (595)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
踩一下
2020-9-4 09:48
0
雪    币: 888
活跃值: (9861)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
21
wanttobeno 跟着楼主30天学习
别掉队呀 开车很快的
2020-9-4 09:52
0
雪    币: 5596
活跃值: (2173)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
xor eax,eax
xor ebx,ebx
xor ecx,ecx
mov eax,1
add eax,1   ### 这里按照下面的,不是应该add eax,2?
mov ebx,eax
mov ecx,3


2020-9-4 13:44
0
雪    币: 888
活跃值: (9861)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
23
wanttobeno xor eax,eax xor ebx,ebx xor ecx,ecx mov eax,1 add e ...
对的,应该是add eax,2 我写错了. 流水线优化那块吧.我编辑一下.
2020-9-4 13:59
0
雪    币: 26185
活跃值: (63317)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
24

欢迎更多的小伙伴参与到 #30天写作挑战#中来!活动详情:https://bbs.pediy.com/thread-261705.htm

2020-9-7 16:54
0
游客
登录 | 注册 方可回帖
返回
//