在C语言中,字符串其实就是一个特殊的数组,一个以零结尾的字符数组而已,所以对于定位字符串中的字符的话可以参考上一篇博客-数组。这篇博客主要用于记录字符串的一些操作函数,以便于在逆向识别的时候可以顺利的还原为函数。这里因为在release版下其字符串操作函数会内嵌汇编,也就是说并不是使用call来调用函数,所以我们需要来逆向识别一下。
所以下面我们讨论的都是release版下的情况,并且使用的编译器为vc6.0,为什么使用这款编译器呢,因为这款编译器编译出来的字符串操作函数是有无分支优化的,而对于高版本的vs来说,使用的就是我们平常的逻辑(循环处理函数),高版本比较好识别。虽然vc6.0版本比较老了,就算我们平常遇不到,但是对于无分支优化的手段还是很值得我们去学习的,体会一下汇编的艺术。
下面我们主要来看一下以下几个函数的实现
strlen
strcpy
memcpy
strcmp
先来看第一个strlen
int main(int argc, char* argv[])
{
return strlen("Hello World!\n");
}
对应的汇编代码
.text:00401000 push edi
.text:00401001 mov edi, offset aHelloWorld ; "Hello World!\n"
.text:00401006 or ecx, 0FFFFFFFFh //相当于ecx=-1,无符号下为最大的整数
.text:00401009 xor eax, eax //eax=0
.text:0040100B repne scasb //字符串扫描函数,当ecx不为0或者和al比较不相等时继续
.text:0040100D not ecx
.text:0040100F dec ecx
.text:00401010 pop edi
.text:00401011 mov eax, ecx
.text:00401013 retn
对于上面的汇编代码先简单的分析一下,可以发现其并未用到循环,但是从其字符串扫描函数来看,其相当于做了一个循环(处理器有优化),对于上面的字符串扫描函数,也就是说当遇到字符串的结尾字符0时便会退出,而在扫描过程中ecx也会随之一直减。说到这里其实大家心里应该就有个概念了,此时减去的ecx的个数应该就是字符串长度,但是此时ecx也包括了最后的结尾0,而字符串长度是不包含结尾0的,所以在最后一处又使用dec减一获取正确的字符串长度。
ecx = 0xFFFFFFFF - len - 1 (末尾0)
ecx = -2-len
len = -2-ecx
len = -2 &