C-编码与if逆向

裸函数实现加法运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


int __declspec(naked) add(int x,int y,int z)
{
__asm
{
//保存栈底
push ebp
//提升堆栈
mov ebp,esp
sub esp,0x40
//保存现场
push ebx
push esi
push edi
//缓冲区数据填充
mov eax,0xCCCCCCCC
mov ecx,0x10
lea edi,dword ptr ds:[ebp-0x40]
rep stosd
//函数实际操作
mov dword ptr ds:[ebp-0x4],1
mov dword ptr ds:[ebp-0x8],2
mov dword ptr ds:[ebp-0xc],3
mov eax,dword ptr ds:[ebp+0x8]
add eax,dword ptr ds:[ebp+0xc]
add eax,dword ptr ds:[ebp+0x10]
add eax,dword ptr ds:[ebp-0x4]
add eax,dword ptr ds:[ebp-0x8]
add eax,dword ptr ds:[ebp-0xc]
//还原现场
pop edi
pop esi
pop ebx
//还原堆栈
mov esp,ebp
pop ebp
//根据返回地址到下一条命令
ret
}

}

int main(int argc, char* argv[])
{
add(1,2,3);
return 0;

}

编码

ASCII编码表

十进制的数值对应的字符,使用指定的七位或者八位二进制数组合来表示128或256钟字符,标准ASCII表用七位,最高位永远是0

image-20230424141550746

扩展ASCII码表

八位全用上,但是仍然只适用在英文上

GB2312

为了显示中文,必须有一套编码规则用于将汉字转换为计算机可以接受的数字系统,为了区分中英文混合的文本,标准ASCII码表最高位都是0,我们汉字的编码最高位都是1,用于区分

GB2312采用双字节编码,每个字符占两个字节,其中第一个字节为0xA1-0xF7,第二个字节为0xA1-0xFE。

其中第一个字节表示这个字符在GB2312字符表中所处“区”的编号,第二个字节表示这个字符在这个区中的位置

image-20230424143120075

内存图示

image-20230424175520978

if语句逆向

if

看到影响标志位的汇编语句,紧跟着一句cmp指令和JCC,那么这几条语句很有可能就是if语句执行的内存区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stdafx.h"

int g_n = 0;

void add(int x,int y)
{
if(x>y)
{
g_n=x;
}
}

int main(int argc, char* argv[])
{
add(2,3);
return 0;

}

image-20230424181734623

if…else

判断if语句和if else语句的区别就在于,JCC指令跳转到的地方的上一句指令是不是jmp,jmp跳到了堆栈还原ESI,EDI等寄存器的pop指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "stdafx.h"

int g_n = 0;

void add(int x,int y)
{
if(x>y)
{
g_n=x;
}
else
{
g_n=y;
}
}

int main(int argc, char* argv[])
{
add(2,3);
return 0;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
00401020   push        ebp
00401021 mov ebp,esp
00401023 sub esp,40h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-40h]
0040102C mov ecx,10h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]


00401038 mov eax,dword ptr [ebp+8]
0040103B cmp eax,dword ptr [ebp+0Ch]
0040103E jle add+2Bh (0040104b)
//如果x<=y,就跳转到0040104b,把y的值给这个全局变量 ,如果条件不成立就顺序执行
00401040 mov ecx,dword ptr [ebp+8]
00401043 mov dword ptr [g_n (004225c4)],ecx
00401049 jmp add+34h (00401054)
//无条件跳转到00401054,略过else赋值的部分
0040104B mov edx,dword ptr [ebp+0Ch]
0040104E mov dword ptr [g_n (004225c4)],edx


00401054 pop edi
00401055 pop esi
00401056 pop ebx
00401057 mov esp,ebp
00401059 pop ebp
0040105A ret

if…else if…else if…else

add esp,0Ch

根据外平栈的语句综合判断参数可能有三个

假设为a[ebp+8],b[ebp+0Ch],c[ebp+10h]

全局变量g_n[0x004225c4]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
0040B500   push        ebp
0040B501 mov ebp,esp
0040B503 sub esp,40h
0040B506 push ebx
0040B507 push esi
0040B508 push edi
0040B509 lea edi,[ebp-40h]
0040B50C mov ecx,10h
0040B511 mov eax,0CCCCCCCCh
0040B516 rep stos dword ptr [edi]
//g_n (004225c4)全局变量
//0x0040b55a函数体结束位置

0040B518 mov eax,dword ptr [ebp+8]
0040B51B cmp eax,dword ptr [ebp+0Ch]
0040B51E jle add+2Bh (0040b52b)
0040B520 mov ecx,dword ptr [ebp+8]
0040B523 mov dword ptr [g_n (004225c4)],ecx
0040B529 jmp add+5Ah (0040b55a)
//if(a>b){g_n=a;}

0040B52B mov edx,dword ptr [ebp+0Ch]
0040B52E cmp edx,dword ptr [ebp+10h]
0040B531 jle add+3Dh (0040b53d)
0040B533 mov eax,dword ptr [ebp+0Ch]
0040B536 mov [g_n (004225c4)],eax
0040B53B jmp add+5Ah (0040b55a)
//else if(b>c){g_n=b;}

0040B53D mov ecx,dword ptr [ebp+10h]
0040B540 cmp ecx,dword ptr [ebp+8]
0040B543 jle add+50h (0040b550)
0040B545 mov edx,dword ptr [ebp+10h]
0040B548 mov dword ptr [g_n (004225c4)],edx
0040B54E jmp add+5Ah (0040b55a)
//else if(c>a){g_n=c;}

0040B550 mov eax,[g_n (004225c4)]
0040B555 mov [g_n (004225c4)],eax
//else{g_n=g_n;}

0040B55A pop edi
0040B55B pop esi
0040B55C pop ebx
0040B55D mov esp,ebp
0040B55F pop ebp
0040B560 ret

判断else if

1、没个条件跳转指令要跳去的地址前面都有jmp

2、这些jmp指令的地址都一样

3、没有条件判断的分支为else部分

源代码,这些代码没有意义,单纯为了逆向乱写的逻辑,重点在于else if语句的逆向上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "stdafx.h"

int g_n = 0;

void add(int x,int y,int z)
{
if(x>y)
{
g_n=x;
}
else if(y>z)
{
g_n=y;
}
else if(z>x)
{
g_n=z;
}
else
{
g_n=g_n;
}
}

int main(int argc, char* argv[])
{
add(1,2,3);
return 0;

}