C 理解将对象反编译为源代码
首先,我是一名学生,我还没有关于C、C++和汇编程序的广泛知识,所以我正在竭尽全力去理解它 我有一段来自英特尔x86-32位处理器的汇编代码 我的目标是将其转换为源代码C 理解将对象反编译为源代码,c,assembly,x86,reverse-engineering,C,Assembly,X86,Reverse Engineering,首先,我是一名学生,我还没有关于C、C++和汇编程序的广泛知识,所以我正在竭尽全力去理解它 我有一段来自英特尔x86-32位处理器的汇编代码 我的目标是将其转换为源代码 0x80483dc <main>: push ebp 0x80483dd <main+1>: mov ebp,esp 0x80483df <main+3>: sub esp,0x10 0x80483e2 <mai
0x80483dc <main>: push ebp
0x80483dd <main+1>: mov ebp,esp
0x80483df <main+3>: sub esp,0x10
0x80483e2 <main+6>: mov DWORD PTR [ebp-0x8],0x80484d0
0x80483e9 <main+13>: lea eax,[ebp-0x8]
0x80483ec <main+16>: mov DWORD PTR [ebp-0x4],eax
0x80483ef <main+19>: mov eax,DWORD PTR [ebp-0x4]
0x80483f2 <main+22>: mov edx,DWORD PTR [eax+0xc]
0x80483f5 <main+25>: mov eax,DWORD PTR [ebp-0x4]
0x80483f8 <main+28>: movzx eax,WORD PTR [eax+0x10]
0x80483fc <main+32>: cwde
0x80483fd <main+33>: add edx, eax
0x80483ff <main+35>: mov eax,DWORD PTR [ebp-0x4]
0x8048402 <main+38>: mov DWORD PTR [eax+0xc],edx
0x8048405 <main+41>: mov eax,DWORD PTR [ebp-0x4]
0x8048408 <main+44>: movzx eax,BYTE PTR [eax]
0x804840b <main+47>: cmp al,0x4f
0x804840d <main+49>: jne 0x8048419 <main+61>
0x804840f <main+51>: mov eax,DWORD PTR [ebp-0x4]
0x8048412 <main+54>: movzx eax,BYTE PTR [eax]
0x8048415 <main+57>: cmp al,0x4b
0x8048417 <main+59>: je 0x804842d <main+81>
0x8048419 <main+61>: mov eax,DWORD PTR [ebp-0x4]
0x804841c <main+64>: mov eax,DWORD PTR [eax+0xc]
0x804841f <main+67>: mov edx, eax
0x8048421 <main+69>: and edx,0xf0f0f0f
0x8048427 <main+75>: mov eax,DWORD PTR [ebp-0x4]
0x804842a <main+78>: mov DWORD PTR [eax+0x4],edx
0x804842d <main+81>: mov eax,0x0
0x8048432 <main+86>: leave
0x8048433 <main+87>: ret
价值观:
0x4 = 4
0x8 = 8
0xc = 12
0x10 = 16
0x4b = 75
0x4f = 79
类型:
char (8 bits) = 1 BYTE
short (16 bits) = WORD
int (32 bit) = DWORD
long (32 bits) = DWORD
long long (32 bit) = DWORD
这就是我能够创造的:
#include <stdio.h>
int main (void)
{
int a = 0x80484d0;
int b
short c;
int d;
c + b?
if (79 <= al) {
instructions
} else {
instructions
}
return 0
}
这对你有什么意义吗?有人能给我解释一下吗?
有人真的这样编程吗
非常感谢 x86汇编语言继承了悠久的历史,并且基本上保持了兼容性。我们需要回到故事开始的8086/8088芯片。这些是16位处理器,这意味着它们的寄存器的字大小为16位。通用寄存器被命名为AX、BX、CX和DX。8086具有操作这些寄存器的上下8位部分的指令,这些寄存器被命名为AH、AL、BH、BL、CH、CL、DH和DL。描述这个,请看一看 这些寄存器的32位版本前面有一个
E
:EAX、EBX、ECX等
您提到的特定指令,例如,cmp al,0x4f
正在将AX寄存器的低位字节与0x4f进行比较。比较实际上与减法相同,但不保存结果,只设置标志
对于8086指令集。您的程序是32位代码,因此您至少需要一个80386指令参考。您已经分析了变量,这是一个很好的起点。您应该尝试在开始时向它们添加类型注释、大小,以及当用作指针(如
b
)时,指向什么类型/大小的指针
知道[ebp-4]
是b
,我可能会按如下方式更新变量表:
c = [b + 0xc]
d = [b + 0x10]
e = [b + 0], size = byte
另一个需要分析的是控制流。对于大多数指令来说,控制流是顺序的,但某些指令故意改变它。广义地说,当电脑向前移动时,它会跳过一些代码,而当电脑向后移动时,它会重复一些已经运行过的代码。跳过代码用于构造if-then、if-then-else和断开循环的语句。跳回用于继续循环 有些指令称为条件分支,在某些动态条件为真时:向前跳(或向后跳),在为假时,执行简单的顺序前进到下一条指令(有时称为条件分支失效) 此处的控制顺序为:
...
0x8048405 <main+41>: mov eax,DWORD PTR [ebp-0x4] b
0x8048408 <main+44>: movzx eax,BYTE PTR [eax] b->e
0x804840b <main+47>: cmp al,0x4f b->e <=> 'O'
0x804840d <main+49>: jne 0x8048419 <main+61> b->e != 'O' skip to 61
** we know that the letter, a->e, must be 'O' here
0x804840f <main+51>: mov eax,DWORD PTR [ebp-0x4] b
0x8048412 <main+54>: movzx eax,BYTE PTR [eax] b->e
0x8048415 <main+57>: cmp al,0x4b b->e <=> 'K'
0x8048417 <main+59>: je 0x804842d <main+81> b->e == 'K' skip to 81
** we know that the letter, a->e must not be 'K' here if we fall thru the above je
** this line can be reached by taken branch jne or by fall thru je
0x8048419 <main+61>: mov eax,DWORD PTR [ebp-0x4] ******
...
由于这两个条件分支是函数中唯一的流控制修改,因此if没有其他部分,也没有循环或其他if
此代码似乎有一个小问题 如果该值不是“O”,则部件将从第一次测试开始点火。然而,如果我们达到第二个测试,我们已经知道字母是“O”,所以测试字母“K”是愚蠢的,并且是正确的(“O”不是“K”) 因此,这个if-then将始终启动
它要么效率很低,要么存在一个bug,可能是字符串中的下一个字母(可能是)应该测试“K”而不是同一个字母。您的程序集完全疯了。这大致相当于C:
intmain(){
int i=0x80484d0;//在ebp-8中
int*p=&i;//在ebp-4中
p[3]+=(短)p[4];//将argc添加到返回地址(!)
if((char)*p!=0x4f | | |(char)*p!=0x4b)//由于| |而不是&&
p[1]=p[3]&0xf0f;//注意p[1]是p
返回0;
}
很明显,这是非常糟糕的代码,几乎肯定不会达到程序员的目的。
long-long(32位)=DWORD
是不正确的。C++标准要求al
是什么,那么您需要对处理器进行更深入的研究,然后才能理解反汇编或汇编列表。al
寄存器是eax
寄存器的最低有效8位,而ax
是eax
的l.s.16位。类似于bl
、cl
、dl
、bx
、cx
和dx
。另外,ah
是eax
的下8位,因此ah
和al
一起构成ax
。。请看标题为“基本程序执行寄存器”的部分@PeterCordes我认为你没有大脑放屁。我觉得那个集会有点奇怪。特别是,在0x80483f2:mov-edx,DWORD-PTR[eax+0xc]
之后,在我看来,返回地址将在edx
中结束,这似乎是不可取的,因为代码会继续处理它。除非这一章是关于模糊代码,否则我会写信给作者。代码中有一个很小的逻辑错误,而且这本书没有出现在Google上(你给了我们正确的名字吗?),所以我倾向于相信这本书有一个关于控制流模糊处理的精彩章节,或者是由不应该的人写的。[ebp-4]
是b
-不是b
一个指针变量,是否持有ebp-8的地址?因此,从[eax+0xc]
开始的偏移是索引到函数自己的堆栈帧中,同时mov-edx[eax+0xc]
加载函数的返回地址。(Joseph Sible和我;在我们看来这很疯狂。我想知道原始代码是否在本地数组的边界之外建立索引,如char*arr[1]={“hello”};
?)我仍然很困惑。。。但是非常感谢你提供的信息。是否有任何方法可以自动将目标代码转换为源代码,即使它与源代码非常相似。。。但不完全是吗?感谢0x80484d0
可能是一个地址
c = [b + 0xc]
d = [b + 0x10]
e = [b + 0], size = byte
...
0x8048405 <main+41>: mov eax,DWORD PTR [ebp-0x4] b
0x8048408 <main+44>: movzx eax,BYTE PTR [eax] b->e
0x804840b <main+47>: cmp al,0x4f b->e <=> 'O'
0x804840d <main+49>: jne 0x8048419 <main+61> b->e != 'O' skip to 61
** we know that the letter, a->e, must be 'O' here
0x804840f <main+51>: mov eax,DWORD PTR [ebp-0x4] b
0x8048412 <main+54>: movzx eax,BYTE PTR [eax] b->e
0x8048415 <main+57>: cmp al,0x4b b->e <=> 'K'
0x8048417 <main+59>: je 0x804842d <main+81> b->e == 'K' skip to 81
** we know that the letter, a->e must not be 'K' here if we fall thru the above je
** this line can be reached by taken branch jne or by fall thru je
0x8048419 <main+61>: mov eax,DWORD PTR [ebp-0x4] ******
...
if ( a->e != 'O' || a->e != 'K' ) {
then-part
}