怎么解c语言逆向编码,逆向还原C语言代码 练习1

找了个C语言100列 用来练习OD还原C语言代码 至于C+的 以后也会写

我们先来看第一个程序,我们先分析Debug的 Debug为了方便调试,代码都是一对一的翻译 没做什么优化,还原起来比较好上手,

7846f29a95c812a6a3260d9f24e1bf56.png

先用OD载入,我们看到一个GetCommandLineA 我们知道 C语言真正的入口并不是main 而在main之前 会调用GetCommandLineA ,也就是说,我们往下面翻一下 可能会找到main函数,我们往下翻一下

bda89ba6829df33f933181869e9a545e.png

这段代码很可疑,可能传递了3个参数,前面的ecx edx也可能是参数,所以我说可能传递了3个, 然后 call下面 add esp,0xc 表示这个函数是外平栈,那么ecx edx应该不是参数,这个call很可能是main 我们进去看看 是个jmp 再跟过去 打个断点

看到如下的代码:

01b41ccad8e1d9a8213bf2ba673b4a27.png

我鼠标选中的(紫色背景)的代码 是debug版本初始化栈用的,先不管他,看箭头处 这里有个call push进去的参数是”\n” 我们看看这个call是什么,选中这行 按回车键跟过去

6b7b6a5760b626d2137a26010243b62a.png

看这代码 应该是C语言的printf函数没错了,我们加个标签,这样再调用这个函数的时候就能看出来是他了,我们选中这行代码的段首 然后 右键 –标签 或者按快捷键 : 在弹出来的对话框中输入 printf 如下图

718d11493ac2d5076376451061ee3c3b.png

这样 以后调用printf的地方就会显示出来了,看下面的效果

e993d07b7f106f2bd8ffe86a79a464ea.png

OK ~

我们看看Call的下面的代码

bc41cf6d340f0eeec035bd3f84618986.png

代码有点多,先不急,我们先简单的浏览下 我们知道 ebp+4是函数返回地址 ebp+8 +c ….是函数的参数,而ebp-4 -8 ……是函数的局部变量,简单的看一下,这一段代码里面 到retn之前有3个ebp- 也就是有3个参数咯~ 我们来简单规定下 ebp-4 我们叫他i -8 叫j -c叫k

00401035 |. C745 FC 01000>mov dword ptr ss:[ebp-0x4],0x1

0040103C |. EB 09 jmp short Test1_Dd.00401047

0040103E |> 8B45 FC /mov eax,dword ptr ss:[ebp-0x4]

00401041 |. 83C0 01 |add eax,0x1

00401044 |. 8945 FC |mov dword ptr ss:[ebp-0x4],eax ; kernel32.BaseThreadInitThunk

00401047 |> 837D FC 05 cmp dword ptr ss:[ebp-0x4],0x5

0040104B  |. /7D 67         |jge short Test1_Dd.004010B4

我们先看下这一段,先给i赋值1 然后立马就跳了,跳到和5比较的地方了,然后判断 如果大于5 又跳了,我们看看他跳过去的地方的代码

004010B4 |> \33C0 xor eax,eax ; kernel32.BaseThreadInitThunk

004010B6 |. 5F pop edi ; kernel32.7578336A

004010B7 |. 5E pop esi ; kernel32.7578336A

004010B8 |. 5B pop ebx ; kernel32.7578336A

004010B9 |. 83C4 4C add esp,0x4C

也就是说 大于5 就结束了 如果小于5的话 就执行

0040104D |. C745 F8 01000>|mov dword ptr ss:[ebp-0x8],0x1

00401054 |. EB 09 |jmp short Test1_Dd.0040105F

00401056 |> 8B4D F8 |/mov ecx,dword ptr ss:[ebp-0x8] ; kernel32.7578336A

00401059 |. 83C1 01 ||add ecx,0x1

0040105C |. 894D F8 ||mov dword ptr ss:[ebp-0x8],ecx

0040105F |> 837D F8 05 | cmp dword ptr ss:[ebp-0x8],0x5

00401063 |. /7D 4D ||jge short Test1_Dd.004010B2

也就说 如果小于5的话 就执行j=1 然后判断j是不是大于5 如果大于5的话 就跳转 看看跳到哪里去了

004010B2  |>^\EB 8A         \jmp short Test1_Dd.0040103E

调到一个jmp 我们再看看jmp跳过去的地方的代码

0040103E |> /8B45 FC /mov eax,dword ptr ss:[ebp-0x4]

00401041 |. |83C0 01 |add eax,0x1

00401044 |. |8945 FC |mov dword ptr ss:[ebp-0x4],eax ; kernel32.BaseThreadInitThunk

00401047 |> |837D FC 05 cmp dword ptr ss:[ebp-0x4],0x5

0040104B |. |7D 67 |jge short Test1_Dd.004010B4

是不是有点眼熟,刚才判断i小于5的地方么?而且在判断之前还对i+1了

那么我们就能确定了 最起码 j外面有个for循环 代码应该是这样

for (i=1;i<5;i++)

{

j = 1;

if(j<5)

{

}

}

我们再看看 刚刚判断j大于5的那里 如果小于5会怎么样

00401065 |. C745 F4 01000>||mov dword ptr ss:[ebp-0xC],0x1

0040106C |. EB 09 ||jmp short Test1_Dd.00401077

0040106E |> 8B55 F4 ||/mov edx,dword ptr ss:[ebp-0xC]

00401071 |. 83C2 01 |||add edx,0x1

00401074 |. 8955 F4 |||mov dword ptr ss:[ebp-0xC],edx ; Test1_Dd.

00401077 |> 837D F4 05 || cmp dword ptr ss:[ebp-0xC],0x5

0040107B |. 7D 33 |||jge short Test1_Dd.004010B0

嗯?如果j

004010B0  |>^\EB A4         |\jmp short Test1_Dd.00401056

又是一个jmp 看看跳过去的地址,我们分析分析

00401056 |> /8B4D F8 |/mov ecx,dword ptr ss:[ebp-0x8] ; kernel32.7578336A

00401059 |. |83C1 01 ||add ecx,0x1

0040105C |. |894D F8 ||mov dword ptr ss:[ebp-0x8],ecx

0040105F |> |837D F8 05 | cmp dword ptr ss:[ebp-0x8],0x5

00401063 |. |7D 4D ||jge short Test1_Dd.004010B2

这明显是比较j小于5的代码 而且是调到j+1的地方

那么 我们的更新刚才还原出来的代码了

应该是这样

for (i=1;i<5;i++)

{

for (j=1;j<5;j++)

{

k=1;

if(k<5)

{}

}

}

好,我们在看看 k如果不跳会怎么样

0040107D |. 8B45 FC |||mov eax,dword ptr ss:[ebp-0x4]

00401080 |. 3B45 F4 |||cmp eax,dword ptr ss:[ebp-0xC]

00401083 |. 74 29 |||je short Test1_Dd.004010AE

00401085 |. 8B4D FC |||mov ecx,dword ptr ss:[ebp-0x4]

00401088 |. 3B4D F8 |||cmp ecx,dword ptr ss:[ebp-0x8] ; kernel32.7578336A

0040108B |. 74 21 |||je short Test1_Dd.004010AE

0040108D |. 8B55 F8 |||mov edx,dword ptr ss:[ebp-0x8] ; kernel32.7578336A

00401090 |. 3B55 F4 |||cmp edx,dword ptr ss:[ebp-0xC]

00401093 |. 74 19 |||je short Test1_Dd.004010AE

00401095 |. 8B45 F4 |||mov eax,dword ptr ss:[ebp-0xC]

00401098 |. 50 |||push eax ; kernel32.BaseThreadInitThunk

00401099 |. 8B4D F8 |||mov ecx,dword ptr ss:[ebp-0x8] ; kernel32.7578336A

0040109C |. 51 |||push ecx

0040109D |. 8B55 FC |||mov edx,dword ptr ss:[ebp-0x4]

004010A0 |. 52 |||push edx ; Test1_Dd.

004010A1 |. 68 1C204200 |||push Test1_Dd.0042201C ; ASCII "%d,%d,%d\n"

004010A6 |. E8 55000000 |||call

004010AB |. 83C4 10 |||add esp,0x10

好吧~k如果不跳 执行的代码有点小多。。。先不管,我们看到k里面有3个跳转,跳转的目标地址都一样 我们看看跳过去会怎么样

004010AE  |>^\EB BE         ||\jmp short Test1_Dd.0040106E

跳过去又是一个jmp 难道k也是循环?我们过去看看

0040106E  |> /8B55 F4       ||/mov edx,dword ptr ss:[ebp-0xC]

00401071  |. |83C2 01       |||add edx,0x1

00401074  |. |8955 F4       |||mov dword ptr ss:[ebp-0xC],edx        ;  Test1_Dd.

00401077  |> |837D F4 05    || cmp dword ptr ss:[ebp-0xC],0x5

0040107B  |. |7D 33         |||jge short Test1_Dd.004010B0

果然,k也是循环 那么 我们目前还原出来的代码应该是这样

int i,j,k;

for(i=1;i<5;i++)

{

for(j=1;j<5;j++)

{

for(k=1;k<5;k++)

{

}

}

}

好了 接着 我们来看看k这个循环里面的代码

0040107D |. 8B45 FC |||mov eax,dword ptr ss:[ebp-0x4]

00401080 |. 3B45 F4 |||cmp eax,dword ptr ss:[ebp-0xC] ; Test1_Dd.00404270

00401083 |. 74 29 |||je short Test1_Dd.004010AE

00401085 |. 8B4D FC |||mov ecx,dword ptr ss:[ebp-0x4]

00401088 |. 3B4D F8 |||cmp ecx,dword ptr ss:[ebp-0x8] ; Test1_Dd.00422138

0040108B |. 74 21 |||je short Test1_Dd.004010AE

0040108D |. 8B55 F8 |||mov edx,dword ptr ss:[ebp-0x8] ; Test1_Dd.00422138

00401090 |. 3B55 F4 |||cmp edx,dword ptr ss:[ebp-0xC] ; Test1_Dd.00404270

00401093 |. 74 19 |||je short Test1_Dd.004010AE

00401095 |. 8B45 F4 |||mov eax,dword ptr ss:[ebp-0xC] ; Test1_Dd.00404270

00401098 |. 50 |||push eax

00401099 |. 8B4D F8 |||mov ecx,dword ptr ss:[ebp-0x8] ; Test1_Dd.00422138

0040109C |. 51 |||push ecx

0040109D |. 8B55 FC |||mov edx,dword ptr ss:[ebp-0x4]

004010A0 |. 52 |||push edx

004010A1 |. 68 1C204200 |||push Test1_Dd.0042201C ; ASCII "%d,%d,%d\n"

004010A6 |. E8 55000000 |||call

004010AB |. 83C4 10 |||add esp,0x10

看到这么多代码 先不要慌,我们先 一句一句来读 ,下面的代码跟上面一样 但是加了注释

0040107D |. 8B45 FC |||mov eax,dword ptr ss:[ebp-0x4] ; 把i放到eax

00401080 |. 3B45 F4 |||cmp eax,dword ptr ss:[ebp-0xC] ; 比较i和k

00401083 |. 74 29 |||je short Test1_Dd.004010AE ; 如果相等就调到4010ae

00401085 |. 8B4D FC |||mov ecx,dword ptr ss:[ebp-0x4] ; 取出i 放到ecx

00401088 |. 3B4D F8 |||cmp ecx,dword ptr ss:[ebp-0x8] ; 比较i和k

0040108B |. 74 21 |||je short Test1_Dd.004010AE ; 如果相等就跳到4010ae

0040108D |. 8B55 F8 |||mov edx,dword ptr ss:[ebp-0x8] ; 取出j

00401090 |. 3B55 F4 |||cmp edx,dword ptr ss:[ebp-0xC] ; 比较k和j

00401093 |. 74 19 |||je short Test1_Dd.004010AE ; 相等就跳转

00401095 |. 8B45 F4 |||mov eax,dword ptr ss:[ebp-0xC] ; 如果i不等于k 且i不等于j 且j不等于k就会执行这里

00401098 |. 50 |||push eax ; 上面那里是取出k 这一句把k压入栈中

00401099 |. 8B4D F8 |||mov ecx,dword ptr ss:[ebp-0x8] ; 取出j

0040109C |. 51 |||push ecx ; 入栈

0040109D |. 8B55 FC |||mov edx,dword ptr ss:[ebp-0x4] ; 取出i

004010A0 |. 52 |||push edx ; 入栈

004010A1 |. 68 1C204200 |||push Test1_Dd.0042201C ; ASCII "%d,%d,%d\n"

004010A6 |. E8 55000000 |||call ; 这里调用print函数

通过上面的注释可以得出一个结论,这里是判断如果 i j k互不相等 就输出 也就是说 能还原出如下代码

int i,j,k;

for(i=1;i<5;i++)

{

for(j=1;j<5;j++)

{

for(k=1;k<5;k++)

{

if(i != k)

{

if(i != j)

{

if(j != k)

{

printf("%d,%d,%d",i,j,k);

}

}

}

}

}

}

3个if我们可以用 && 优化一下 最终的结果如下

int i,j,k;

for(i=1;i<5;i++)

{

for(j=1;j<5;j++)

{

for(k=1;k<5;k++)

{

if(i != k && i != j && j != k)

{

printf("%d,%d,%d",i,j,k);

}

}

}

}

打赏作者

a41b0efb0576f688d1dd887f454189a9.png微信、支付宝扫一扫,鼓励一下作者吧~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值