10 全局变量初始化,数组的识别

1. 全局变量通过函数初始化

初始化时机在main函数之前,对于VC6,具体来说是在mainCRTStartup -> _cinit -> 2_initterm中。此函数接收2个参数,通过遍历,找到函数指针并调用。逆向时找到push两个参数的地方,以这2个参数作为地址的上下边界,寻找其中非0的值,在反汇编窗口中查看函数逻辑,判断是否是我们需要的函数。

 

#ifdef CRTDLL

void __cdecl _initterm (

#else  /* CRTDLL */

static void __cdecl _initterm (

#endif  /* CRTDLL */

        _PVFV * pfbegin,

        _PVFV * pfend

        )

{        

        while ( pfbegin < pfend )

        {

            if ( *pfbegin != NULL )

                (**pfbegin)();

            ++pfbegin;

        }

}

 

 

 

 

1. 全局变量通过函数初始化

初始化时机在main函数之前,对于VC6,具体来说是在mainCRTStartup -> _cinit -> 2_initterm中。此函数接收2个参数,通过遍历,找到函数指针并调用。逆向时找到push两个参数的地方,以这2个参数作为地址的上下边界,寻找其中非0的值,在反汇编窗口中查看函数逻辑,判断是否是我们需要的函数。

 

#ifdef CRTDLL

void __cdecl _initterm (

#else  /* CRTDLL */

static void __cdecl _initterm (

#endif  /* CRTDLL */

        _PVFV * pfbegin,

        _PVFV * pfend

        )

{        

        while ( pfbegin < pfend )

        {

            if ( *pfbegin != NULL )

                (**pfbegin)();

            ++pfbegin;

        }

}

 

 

 

 

VS2019mainCRTStartup -> 2_initterm中,同样在地址的上下边界寻找非0的值,可能会发现不止一个非0值,一般第一个非0值都是系统相关的代码,可略过。

 

2. 识别数组

2.1 数组特性:

(1) 连续性:相邻数据无重叠、无对齐

(2) 一致性:类型一致,作用(业务逻辑)一致

 

论证上述两点的方法:

(1) 使用比例因子寻址方式:[ebp + XXX * ecx*4],利用对ecx所做的检查确定数组边界。也可能存在寄存器化的指针,每次解引用指针并递增指针到下一个位置,此时通过指针递增的步长找到数组元素的size,通过循环次数确定数组元素个数。

(2) 循环结构处理连续空间中的相邻元素:利用循环边界确定数组的边界。

(3) 在高版本编译器中,往往会使用媒体指令一次复制多个数据来初始化数组。

 

2.2 数组寻址公式

type ary[M] = ...

&ary[i] = (int)ary + sizeof(type) * i

 

IDA中识别出数组首地址后,对首地址命名,再按*指定数组元素个数,可令其显示为:-00000014 ary             dd 5 dup(?)

 

同时反汇编窗口也会更新显示效果:

 

 

2.3 二维数组

type ary[M][N] = ...

&ary[i][j] = (int)ary +  sizeof(type[N])*i + sizeof(type)*j

            = (int)ary +  sizeof(type)*i*N + sizeof(type)*j

                = (int)ary +  sizeof(type) * (N*i+j)

debug:

 

 

release:

 

 

 

 

VS2019使用媒体指令初始化数组,其他和VC6一致。

 

2.4 三维数组

type ary[L][M][N] = ...

&ary[i][j][k] = int(ary) + sizeof(type [M][N])*i

+ sizeof(type [N])*j

+ sizeof(type)*k

 

               = int(ary) + sizeof(type)*i*M*N

                           + sizeof(type)*j*N

                           + sizeof(type)*k

 

               = int(ary) + sizeof(type)(i*M*N + j*N +k)

               = int(ary) + sizeof(type)(N*(i*M + j) +k)

debug:

 

 

release:

 

 

根据分析推测出三维数组 type ary[L][M][N]:

i*24 =>  sizeof(type[M][N])==24

j*12 => sizeof(type[N])=12

k*4 => sizeof(type)==4

 

暂停typeint,整理得

sizeof(int)*M*N == 24

sizeof(int)*N == 12

 

即:N=3M=2,即int ary[][2][3]=...

 

 

同样,遍历时依然当作一维数组,循环2*2*3次。

 

 

3. 指针的识别

 

3.1 识别方法:

 

(1) 是否保存了地址

 

(2) 某个寄存器或内存是否为间接访问的来源

 

4. 字符串操作

 

4.1 strlen

 

VS2019release:简单的循环结构

 

 

VC6:

 

 

 

lea edi, addr szBuf

or ecx, -1

xor eax, eax

repne scasb ;ecx=-1-length-1

not ecx

dec ecx

 

length = -2-ecx

       = -2+neg(ecx)

       = -2 + not ecx + 1

       = not ecx - 1

 

4.2 strcpy

debug版是循环结构

 

release版:

 

 

4.3 strcmp

VC6release

 

 

VS2019release:

 

 

posted @ 2021-01-05 15:00  八转达人  阅读(534)  评论(0编辑  收藏  举报