[教程]逆向反汇编第六课
2010-11-27 12:43
477 查看
既然要玩逆向,驱动那我们就算不懂但至少要了解下C/C++语言,C++是一门支持OO的语言,对面想对象的软件开发提供了丰富的支持库.但要高效 正确的使用C++中的继承 多态等语言的特性,必须对这些特性性的底层实现有一定得了解.
其实就核心概念而言,C++的对象模型的核心概念并不多,但最核心的是虚函数.虚函数是在程序运行时刻定义的函数,虚函数的地址是不能在编译时刻确定的,它只能在调用即将进行之前加以确定.对所有虚函数引用通常放在一个专用数组--虚函数表中,每个至少使用一个虚函数的对象里面都具有虚函数表指针.虚函数通常通过指向虚函数表的指针间接的加以调用.
将实例的普通成员改编为虚函数调用,来看看VC在虚函数上面是如何处理的.
view plaincopy to clipboardprint?
class CSum
{
public:
virtual int Add(int a,int b)
{
return (a+b);
}
virtual int Sub(int a,int b)
{
return (a-b);
}
};
void main()
{
CSum* pCSum =new CSum;
pCSum->Add(1,2);
pCSum->Sub(1,2);
}
这是C的一个简单代码,我们看反汇编后的代码是如何的样式,
view plaincopy to clipboardprint?
push esi
push 4
call 00401060
add esp,4 ;为新建对象实力分配4字节内存
test eax,eax
je short 00401019
mov dword ptr [eax],4050A0 ;将4050A0h写入创建的对象实例中4050A0h是CSum类虚函数表的指针,表中的元素是CSum类的虚函数,他们指向CSum函数的成员
mov esi,eax ;esi是4050A0hCSum类虚函数表的指针
jmp short 0040101B
xor esi,esi ;用NULL指向对象实例指针,该分支在内存分配失败才会来到,空指针将激活SEH
0040101B:
mov eax,dword ptr [esi] ;eax=**Add[]
push 2
push 1
mov ecx,esi ;ecx=this
call dword ptr [eax] ;对虚函数的调用,此时eax=**Add(),也就是CALL 401040
mov edx,dword ptr [esi]
push 2
push 1
mov ecx,esi
call dword ptr [edx+4]
pop esi
retn
这段代码首先调用new函数分配class所需内存,调用成功后,eax保存了分配的内存指针,然后将对象实例指向CSum类虚函数表4050A0h.
VTBL里有两组数据
[VTBL]=401040h
[VTBL+4]=401050h
进一步看看这两个指针是什么内容,
;401040h内容如下:Add函数
view plaincopy to clipboardprint?
mov eax,dword ptr [esp+8]
mov ecx,dword ptr [esp+4]
add eax,ecx
retn 8
401050h函数如下:Sub 函数
view plaincopy to clipboardprint?
mov eax,dword ptr [esp+4]
mov ecx,dword ptr [esp+8]
sub eax,ecx
retn 8
原来虚函数是通过浙西iangxuhanshubiaode指针间接地加以调用的,程序仍然使用ecx作为this指针的载体传递给虚成员函数,并且利用两次间接寻址,得到虚函数的正确地址,从而执行
view plaincopy to clipboardprint?
mov eax,dword ptr [esi] ;eax=*指针=**Add()
push 2
push 1
mov ecx,esi ;ecx=this
call dword ptr [eax]
其实就核心概念而言,C++的对象模型的核心概念并不多,但最核心的是虚函数.虚函数是在程序运行时刻定义的函数,虚函数的地址是不能在编译时刻确定的,它只能在调用即将进行之前加以确定.对所有虚函数引用通常放在一个专用数组--虚函数表中,每个至少使用一个虚函数的对象里面都具有虚函数表指针.虚函数通常通过指向虚函数表的指针间接的加以调用.
将实例的普通成员改编为虚函数调用,来看看VC在虚函数上面是如何处理的.
view plaincopy to clipboardprint?
class CSum
{
public:
virtual int Add(int a,int b)
{
return (a+b);
}
virtual int Sub(int a,int b)
{
return (a-b);
}
};
void main()
{
CSum* pCSum =new CSum;
pCSum->Add(1,2);
pCSum->Sub(1,2);
}
class CSum { public: virtual int Add(int a,int b) { return (a+b); } virtual int Sub(int a,int b) { return (a-b); } }; void main() { CSum* pCSum =new CSum; pCSum->Add(1,2); pCSum->Sub(1,2); }
这是C的一个简单代码,我们看反汇编后的代码是如何的样式,
view plaincopy to clipboardprint?
push esi
push 4
call 00401060
add esp,4 ;为新建对象实力分配4字节内存
test eax,eax
je short 00401019
mov dword ptr [eax],4050A0 ;将4050A0h写入创建的对象实例中4050A0h是CSum类虚函数表的指针,表中的元素是CSum类的虚函数,他们指向CSum函数的成员
mov esi,eax ;esi是4050A0hCSum类虚函数表的指针
jmp short 0040101B
xor esi,esi ;用NULL指向对象实例指针,该分支在内存分配失败才会来到,空指针将激活SEH
0040101B:
mov eax,dword ptr [esi] ;eax=**Add[]
push 2
push 1
mov ecx,esi ;ecx=this
call dword ptr [eax] ;对虚函数的调用,此时eax=**Add(),也就是CALL 401040
mov edx,dword ptr [esi]
push 2
push 1
mov ecx,esi
call dword ptr [edx+4]
pop esi
retn
push esi push 4 call 00401060 add esp,4 ;为新建对象实力分配4字节内存 test eax,eax je short 00401019 mov dword ptr [eax],4050A0 ;将4050A0h写入创建的对象实例中4050A0h是CSum类虚函数表的指针,表中的元素是CSum类的虚函数,他们指向CSum函数的成员 mov esi,eax ;esi是4050A0hCSum类虚函数表的指针 jmp short 0040101B xor esi,esi ;用NULL指向对象实例指针,该分支在内存分配失败才会来到,空指针将激活SEH 0040101B: mov eax,dword ptr [esi] ;eax=**Add[] push 2 push 1 mov ecx,esi ;ecx=this call dword ptr [eax] ;对虚函数的调用,此时eax=**Add(),也就是CALL 401040 mov edx,dword ptr [esi] push 2 push 1 mov ecx,esi call dword ptr [edx+4] pop esi retn
这段代码首先调用new函数分配class所需内存,调用成功后,eax保存了分配的内存指针,然后将对象实例指向CSum类虚函数表4050A0h.
VTBL里有两组数据
[VTBL]=401040h
[VTBL+4]=401050h
进一步看看这两个指针是什么内容,
;401040h内容如下:Add函数
view plaincopy to clipboardprint?
mov eax,dword ptr [esp+8]
mov ecx,dword ptr [esp+4]
add eax,ecx
retn 8
mov eax,dword ptr [esp+8] mov ecx,dword ptr [esp+4] add eax,ecx retn 8
401050h函数如下:Sub 函数
view plaincopy to clipboardprint?
mov eax,dword ptr [esp+4]
mov ecx,dword ptr [esp+8]
sub eax,ecx
retn 8
mov eax,dword ptr [esp+4] mov ecx,dword ptr [esp+8] sub eax,ecx retn 8
原来虚函数是通过浙西iangxuhanshubiaode指针间接地加以调用的,程序仍然使用ecx作为this指针的载体传递给虚成员函数,并且利用两次间接寻址,得到虚函数的正确地址,从而执行
view plaincopy to clipboardprint?
mov eax,dword ptr [esi] ;eax=*指针=**Add()
push 2
push 1
mov ecx,esi ;ecx=this
call dword ptr [eax]
相关文章推荐
- [教程]逆向反汇编第六课
- [教程]逆向反汇编第九课
- 自制反汇编逆向分析工具 迭代第六版本 (三)
- [教程]逆向反汇编第一课
- [教程]逆向反汇编第二课
- [教程]逆向反汇编第三课
- [教程]逆向反汇编第四课
- [教程]逆向反汇编第十一课
- 自制反汇编逆向分析工具 迭代第六版本 (四)
- [教程]逆向反汇编第五课
- [教程]逆向反汇编第七课
- 自制反汇编逆向分析工具 迭代第六版本 (一)
- [教程]逆向反汇编第八课
- [教程]逆向反汇编第一课
- 自制反汇编逆向分析工具 迭代第六版本 (五)
- [教程]逆向反汇编第九课
- [教程]逆向反汇编第二课
- [教程]逆向反汇编第三课
- [教程]逆向反汇编第十课
- [教程]逆向反汇编第五课