恶意代码分析-第二十章-C++代码分析
目录
笔记
C语言和C++的不同:面向对象的编程语言,将数据与操作数据的函数都封装到对象中
用类来定义数据类型,保存了函数信息和数据,是一个对象的模板
this指针:原代码
调用HelloWord函数的对象不同,访问存储变量x的内存地址也会不同。this指针在一个不指定对象的函数中对每个变量访问都是隐含的。this参数通常被传递到ECX寄存器中,或者ESI寄存器中。在C++中this指针的调用通常是thiscall,查看反汇编代码,识别thiscall约定是一个识别面向对象代码的简单方法。
汇编代码
对象的开头被保存在栈上的var_10,即1处。ECX获得值,并将这个值作为this的指针使用,即3处。代码访问这个值来获得x。当第二次调用HelloWord时,加载一个不同的指针到ECX中。
重载和修饰:让多个函数使用同一个名字,但接受不同的参数。IDA会反修饰函数名例如[email protected]@@[email protected],其中这个函数是SimpleClass类的一部分,并接受两个整数为参数。
继承:一个子类自动拥有所有父类的函数和数据,且经常定义额外的函数和数据。
虚函数与非虚函数:虚函数是一个可以被子类重写的函数,执行哪一个是在运行时判断的。
虚函数表:添加特殊的结构来支持虚函数(函数指针的数组),每一个虚函数的类都有自己的vtable,类中的每一个虚函数在vtable都有一个项。
在1处访问对象开头的指针,在2处访问这个对象的前四个字节
前四个字节是vtable的指针,而vtable的第一个4字节是指向第一个虚函数代码的指针。
识别虚函数表:
这是一个有着3个虚函数的类的vtable。只有第一个值应该有交叉引用,其他虚函数是按照偏移来索引的,不存在直接访问。但不是被代码直接调用(并不是以call形式出现)。
创建和销毁对象:构造函数:对于不保存在栈上的对象,使用new操作符来分配。
析构函数:在对象离开作用域后自动调用
实验
Lab20-1
new操作符开始,创建一个对象。这个对象的引用会在eax中返回并保存在var_8和var_4中。作为函数调用的this指针传递进去,指向一个URL,然后调用sub_401040
sub_401040
this指针被存储到ebp+var_4中,后又被读取到eax中,然后压入栈
Lab20-2
先初始化Win32的网络功能,然后调用gethostname获得主机名。然后调用sub_401000
sub_401000
这里有一个循环,循环的开始位置是FindFirstFileA,循环的末尾是FindNextFileA。说明在C盘下寻找文件
这里可以看到找的是.doc文件和.pdf文件
如果找到.doc,就会来到这个分支。new操作符新建一个对象,在004011F8和00401204位置,把虚拟函数表写入到了对象的起始偏移位置。判断是虚函数表(因为new创建对象后,马上在对象的起始偏移位置写入了地址4060DC)
而4060DC位置处指向了一个401440的函数指针,其实这里的三个函数是针对.doc,.pdf,什么都没有
这里call [edx]是针对不同的情况调用不同的函数。使用虚函数来对代码修改和扩展变的容易,针对.doc和.pdf
Lab20-3
新建一个对象,并把指针给ecx,之后调用sub_401EE0。这个函数用到了ecx,说明这个函数是这个对象的一个函数
sub_401EE0
之后进去跟入sub_403180
sub_403180
左下方的代码是处理异常,不用分析
反回到mian函数,这是一个循环,循环的上方有sub_401F80函数,循环体内有loc_402410函数,两个函数都使用了ECX,传递之前创建的对象
sub_401F80:是一个从远程获取信息指令的函数
loc_402410:
这个函数里面有一个switch跳转,跳转的值在[esi+4],还要减去0x61(小写字符的a-f)。