吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6976|回复: 20
收起左侧

[原创] 逆向基础之二

  [复制链接]
鱼无论次 发表于 2017-4-14 19:13
本帖最后由 鱼无论次 于 2017-4-14 21:42 编辑

把自己最近的读书笔记与学习心得分享总结,希望各位看官能有所收获吧。
写的有点乱,如果有错误请指正。
不知道为什么我感觉看代码是歪的,可能是我从oneNote复制到有道笔记再复制过来

参考书籍:

C++反汇编与逆向技术

黑客免杀攻防

天书夜谈


需要用到的工具:

IDA

OD

编译环境:VS2013 Debug版


首先附上跳转表:
1.png 2.png


主要内容(不分先后顺序)

1.if-else反汇编

2.for反汇编

3.do-while反汇编与while反汇编(阉割版for循环)

4.总结for、do-while、while最容易记的特征

5.switch-case的三种不同表现方式


1.先来个最简单if语言看下再汇编层是如何体现出来的

渣渣代码:

int nNumberA = 2,nNumberB = 3;

002813DE  mov         dword ptr [nNumberA],2

002813E5  mov         dword ptr [nNumberB],3

if (nNumberA > nNumberB)

002813EC  mov         eax,dword ptr [nNumberA]

002813EF  cmp         eax,dword ptr [nNumberB]            //cmp比较两个操作数做减法,不送回结果,只影响标志位

002813F2  jle            wmain+4Bh (028140Bh)              //我们发现汇编指令满足条件是小于等于则跳转,绕过代码块,好像跟我们写的条件相反。

{

printf("A>B\r\n");

002813F4  mov         esi,esp

002813F6  push        285858h

002813FB  call          dword ptr ds:[289114h]

00281401  add         esp,4                                            //cdecl调用方式在函数内没有任何平衡参数操作,而在退出函数后对esp执行加8操作

00281404  cmp         esi,esp                                        //VS自带的检查堆栈平衡

00281406  call        __RTC_CheckEsp (0281140h)          //这个是VS自带的检查堆栈平衡

}            


我们来做个测试

if (nNumberA == nNumberB)

000313EC  mov         eax,dword ptr [nNumberA]

000313EF  cmp         eax,dword ptr [nNumberB]

000313F2  jne         wmain+4Bh (03140Bh)                   //jnz(不等于)汇编翻译的跳转是跳出去的条件,好像与我们处处作对一样

总结:
       汇编翻译的跳转指令是跳出代码的条件,与你写的条件完全相反。希望各位以后看到汇编翻译的是 jne ,那么你写的条件就是等于


1.2继续if-else if-else代码的反汇编,这里我把VS的一些检查堆栈代码给删掉了

上渣渣代码:

int nNumberA = 5;

00B41A1E  mov         dword ptr [nNumberA],5

if (nNumberA == 2)

00B41A25  cmp         dword ptr [nNumberA],2            

00B41A29  jne         wmain+44h (0B41A44h)                 //不成立跳到下一个if判断

{

printf("nNumberA=2\r\n");

00B41A2B  mov         esi,esp

00B41A2D  push        0B458B0h

00B41A32  call        dword ptr ds:[0B49114h]

00B41A38  add         esp,4                                          //cdecl调用方式在函数内没有任何平衡参数操作,而在退出函数后对esp执行加8操作

00B41A42  jmp         wmain+7Ah (0B41A7Ah)              //如果代码成立执行到这里直接jmp跳出全部判断语句外面

}

else if(nNumberA == 3)

00B41A44  cmp         dword ptr [nNumberA],3

00B41A48  jne         wmain+63h (0B41A63h)               //不成立跳到下一个if判断

{

printf("nNumberA=3\r\n");

00B41A4A  mov         esi,esp

00B41A4C  push        0B45920h

00B41A51  call        dword ptr ds:[0B49114h]

00B41A57  add         esp,4                                          //cdecl调用方式在函数内没有任何平衡参数操作,而在退出函数后对esp执行加8操作

00B41A61  jmp         wmain+7Ah (0B41A7Ah)             //如果代码成立执行到这里直接jmp跳出全部判断语句的外面

}

Else                                                                         //不用判断了什么都不是就直接执行了

{

printf("都不是\r\n");

00B41A63  mov         esi,esp

00B41A65  push        0B459CCh

00B41A6A  call        dword ptr ds:[0B49114h]

00B41A70  add         esp,4

}



2.最强的for循环反汇编

int Sum = 0;

0085139E  mov         dword ptr [Sum],0                     

for (int i = 0; i < 5; i++)

/*************    int i=0   ************/

008513A5  mov         dword ptr ,0                            //这句就是int i=0,只初始化一次,初始化完就没有利用价值了

008513AC  jmp         wmain+37h (08513B7h)              //直接跳到判断语句也就是i<5的地方

/**************  int i = 0  ************/


/**************  i++  **************/

008513AE  mov         eax,dword ptr

008513B1  add         eax,1

008513B4  mov         dword ptr ,eax     

/**************  i++  **************/


/**************  i<5  ***************/

008513B7  cmp         dword ptr ,5

008513BB  jge         wmain+48h (08513C8h)             //还记得我们的汇编翻译特征码?唱反调,不大于等于则跳出去循环外


/**************  i<5  ***************/

008513B7  cmp         dword ptr ,5

008513BB  jge         wmain+48h (08513C8h)             //还记得我们的汇编翻译特征码?唱反调,不大于等于则跳出去循环外


{

Sum = Sum + i;

008513BD  mov         eax,dword ptr [Sum]

008513C0  add         eax,dword ptr

008513C3  mov         dword ptr [Sum],eax   

008513C6  jmp         wmain+2Eh (08513AEh)            //执行完代码跳回去执行i++操作         

}

return 0;

008513C8  xor         eax,eax


我带画张图帮助大家理解,图画的很渣:
3.png

for循环硬生生把i++插到中间去,不是按照我们的思维放在i<5的后面


3.do-while循环与while循环(阉割版for循环)

while (Sum < 5)

008C13A5  cmp         dword ptr [Sum],5         

008C13A9  jge         wmain+36h (08C13B6h)     //一开始就判断

{

Sum++;

008C13AB  mov         eax,dword ptr [Sum]

008C13AE  add         eax,1

008C13B1  mov         dword ptr [Sum],eax

}

008C13B4  jmp         wmain+25h (08C13A5h)    //无条件跳转指令回到循环开始的地方


do-while语句的特征,不管怎么样先执行一遍再说

do

{

Sum = Sum + 1;

00B013A5  mov         eax,dword ptr [Sum]

00B013A8  add          eax,1                                      

00B013AB  mov         dword ptr [Sum],eax           //先执行一遍循环体代码再说

} while (Sum<5);

00B013AE  cmp         dword ptr [Sum],5

00B013B2  jl          wmain+25h (0B013A5h)         //再判断

return 0;

00B013B4  xor         eax,eax


4.总结特征

For有2个jmp

While循环有1个jmp

Do-while没有jmp


5.switch-case的三种不同表现方式

方式一:case<3

代码如下

int NnumA = 2;

00B339CE  mov         dword ptr [NnumA],2

switch (NnumA)

00B339D5  mov         eax,dword ptr [NnumA]

00B339D8  mov         dword ptr [ebp-0D0h],eax

00B339DE  cmp         dword ptr [ebp-0D0h],1       //我们发现switch语句的特点就是把判断全部放在前面

00B339E5  je          wmain+42h (0B339F2h)            

00B339E7  cmp         dword ptr [ebp-0D0h],2

00B339EE  je          wmain+5Fh (0B33A0Fh)

00B339F0  jmp         wmain+7Ah (0B33A2Ah)

{

case 1:

{

printf("%d", NnumA);

00B339F2  mov         esi,esp

00B339F4  mov         eax,dword ptr [NnumA]

00B339F7  push        eax

00B339F8  push        0B358A8h

00B339FD  call        dword ptr ds:[0B39114h]

00B33A03  add         esp,8

00B33A06  cmp         esi,esp

00B33A08  call        __RTC_CheckEsp (0B311D1h)

break;

00B33A0D  jmp         wmain+7Ah (0B33A2Ah)           //跳出判断外面               

}

case 2:

{

printf("%d", NnumA);

00B33A0F  mov         esi,esp

00B33A11  mov         eax,dword ptr [NnumA]

00B33A14  push        eax

00B33A15  push        0B358A8h

00B33A1A  call        dword ptr ds:[0B39114h]

00B33A20  add         esp,8

00B33A23  cmp         esi,esp

00B33A25  call        __RTC_CheckEsp (0B311D1h)

break;

}

}

return 0;

00B33A2A  xor         eax,eax


问题:

       那么我们就滋生出了一个问题:假如我有10甚至100个判断,程序前面就写100个判断语句吗?那么我们来实验下

类似:

Cmp eax,1

Jxxx xxxx

Cmp eax,2

Jxxx xxxx

Cmp eax,3

Jxxx xxxx

Cmp eax,4

……….


这就引出了switch算法的优化问题

方式2:那么就出现我们第二种方式case > 3 并且case < 256

       计算机是很聪明的,会优化算法。索引地址是从0开始的,我写1-4是方便阅读。其实真正是0-3
4.png

这四个值刚好就是我们case的4个值得首地址

部分代码:

case 1:

{

printf("%d", NnumA);

010313BF  mov         eax,dword ptr [NnumA]

}

case 2:

{

printf("%d", NnumA);

010313D3  mov         eax,dword ptr [NnumA]

}

case 3:

{

printf("%d", NnumA);

010313E7  mov         eax,dword ptr [NnumA]

}

case 4:

{

printf("%d", NnumA);

010313FB  mov         eax,dword ptr [NnumA]

}


方式3:大于255就采用了平衡二叉树方式优化算法

假如我们case 1000、700、500、300、100平衡二叉树表现形式

然后我们再上代码:

switch (NnumA)

008913CC  mov         eax,dword ptr [NnumA]

008913CF  mov         dword ptr [ebp-4Ch],eax

008913D2  cmp         dword ptr [ebp-4Ch],1F4h                   //来中间值500做中间值,判断是否大于500

008913D9  jg          wmain+55h (08913F5h)                       //大于500就跳到8913F5H

008913DB  cmp         dword ptr [ebp-4Ch],1F4h                 //判断是否等于500

008913E2  je          wmain+91h (0891431h)                        

008913E4  cmp         dword ptr [ebp-4Ch],64h                   //判断是否等于100

008913E8  je          wmain+0B9h (0891459h)

008913EA  cmp         dword ptr [ebp-4Ch],12Ch                //判断是否等于300

008913F1  je          wmain+0A5h (0891445h)                    

008913F3  jmp         wmain+0CBh (089146Bh)                  //都不是就退出啦

008913F5  cmp         dword ptr [ebp-4Ch],2BCh               //刚才大于500就跳到这里来了,判断是否等于700

008913FC  je          wmain+7Dh (089141Dh)

008913FE  cmp         dword ptr [ebp-4Ch],3E8h               //判断是否等于1000

00891405  je          wmain+69h (0891409h)

00891407  jmp         wmain+0CBh (089146Bh)                //都找不到就退出

自己画的大致图,虽然不是很严谨:
5.png
IDA反汇编图:
6.png

致谢
感谢15PB老师们的辛勤栽培!

免费评分

参与人数 16威望 +1 吾爱币 +26 热心值 +15 收起 理由
Hmily + 1 + 10 + 1 用心讨论,共获提升!
liu101816 + 1 + 1 我很赞同!
大亮studio + 1 + 1 我很赞同!
fkzxwyp + 1 + 1 我很赞同!
myouter + 1 我很赞同!
SomnusXZY + 1 + 1 鼓励转贴优秀软件安全工具和文档!
610100 + 2 + 1 谢谢@Thanks!
gxxxlxy + 1 + 1 谢谢@Thanks!
paradroid + 1 + 1 我很赞同!
网鱼 + 1 + 1 用心讨论,共获提升!
木子木泗 + 1 + 1 谢谢@Thanks!
lipss + 1 + 1 我很赞同!
skeep + 1 + 1 谢谢@Thanks!
lertty + 1 + 1 鼓励转贴优秀软件安全工具和文档!
一个人的回忆 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
wencongwei1998 + 1 + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 鱼无论次 发表于 2017-4-14 22:13
慵懒丶L先森 发表于 2017-4-14 22:09
之前点开发现要250阅读权限吓尿了,感谢用心总结

我在整理,我网路不好没办法保存
 楼主| 鱼无论次 发表于 2018-12-13 09:23
aki阳子 发表于 2017-4-14 20:39
黑山走天涯 发表于 2017-4-14 20:51
学习了!!!!!!!
笑颜一如从前Q 发表于 2017-4-14 20:52
感谢分享
fwwzhen 发表于 2017-4-14 20:57
感谢分享
羊先生没胡子 发表于 2017-4-14 21:47

感谢分享
talent1190 发表于 2017-4-14 21:54
这是好东西,反正看不懂
慵懒丶L先森 发表于 2017-4-14 22:09
之前点开发现要250阅读权限吓尿了,感谢用心总结
yt20090291 发表于 2017-4-14 22:36
谢谢楼主分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 00:21

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表