逆向分析练习四(二叉树的中序遍历)
今天这个题目中包含了递归和结构体,可以充分了解到结构体在内存中的展现形式
题目描述
中序遍历
debug版本的汇编代码
00701A90 push ebp
00701A91 mov ebp,esp
00701A93 sub esp,0CCh
00701A99 push ebx
00701A9A push esi
00701A9B push edi
00701A9C lea edi,[ebp-0CCh]
00701AA2 mov ecx,33h
00701AA7 mov eax,0CCCCCCCCh
00701AAC rep stos dword ptr es:[edi] //熟悉的debug版本的栈初始化
00701AAE mov esi,esp //下面检查栈用的esi
00701AB0 push 7D4h //这里应该是开辟空间的大小
00701AB5 call dword ptr [__imp__malloc (708344h)]
00701ABB add esp,4 //回退栈
00701ABE cmp esi,esp
00701AC0 call @ILT+335(__RTC_CheckEsp) (701154h) //debug中的栈检查
00701AC5 mov dword ptr [res],eax //res = malloc(0x7d4)
00701AC8 mov eax,dword ptr [returnSize] //eax = reurnSize
00701ACB mov dword ptr [eax],0 //*eax = 0
00701AD1 mov eax,dword ptr [returnSize] //*returnSize = 0
00701AD4 push eax //参数
00701AD5 mov ecx,dword ptr [res] //参数
00701AD8 push ecx
00701AD9 mov edx,dword ptr [root] //参数
00701ADC push edx
00701ADD call inorder (7011FEh) //调用了inorder
00701AE2 add esp,0Ch //回退栈
00701AE5 mov eax,dword ptr [res] //res = inorder(root,res,returnSize);
00701AE8 pop edi
00701AE9 pop esi
00701AEA pop ebx
00701AEB add esp,0CCh
00701AF1 cmp ebp,esp
00701AF3 call @ILT+335(__RTC_CheckEsp) (701154h)
00701AF8 mov esp,ebp
00701AFA pop ebp
00701AFB ret
。。。。。。。。。。。。 //这里是被调用的inorder方法
00703580 push ebp
00703581 mov ebp,esp
00703583 sub esp,0C0h
00703589 push ebx
0070358A push esi
0070358B push edi
0070358C lea edi,[ebp-0C0h]
00703592 mov ecx,30h
00703597 mov eax,0CCCCCCCCh
0070359C rep stos dword ptr es:[edi] //下面是inorder的业务代码
0070359E cmp dword ptr [root],0 //if(root == 0)
007035A2 jne inorder+26h (7035A6h) //下面是==0时执行的代码
007035A4 jmp inorder+71h (7035F1h) //==0直接跳到结束所以这应该是个void返回值
007035A6 mov eax,dword ptr [resSize] //if(root != 0)的开始
007035A9 push eax //参数3
007035AA mov ecx,dword ptr [res]
007035AD push ecx //参数2
007035AE mov edx,dword ptr [root]
007035B1 mov eax,dword ptr [edx+4] //这里取root偏移为4的位置简写为root.field2
007035B4 push eax //参数1;可能是个地址DWORD或者一个int
007035B5 call inorder (7011FEh) //调用的还是inorder所以是个地址
007035BA add esp,0Ch
007035BD mov eax,dword ptr [resSize] //eax = resSize
007035C0 mov ecx,dword ptr [eax] //ecx = *resSize
007035C2 mov edx,dword ptr [res] //edx = res
007035C5 mov eax,dword ptr [root] //eax = root
007035C8 mov eax,dword ptr [eax] //eax = *root
007035CA mov dword ptr [edx+ecx*4],eax //res[resSize] = root.field1
007035CD mov ecx,dword ptr [resSize] //ecx = resSize
007035D0 mov edx,dword ptr [ecx] //edx = *resSize
007035D2 add edx,1 //edx++
007035D5 mov eax,dword ptr [resSize] //eax = resSize
007035D8 mov dword ptr [eax],edx //*resSize = (*resSize)++;
007035DA mov eax,dword ptr [resSize] //这里开始又在调用inorder
007035DD push eax
007035DE mov ecx,dword ptr [res]
007035E1 push ecx
007035E2 mov edx,dword ptr [root]
007035E5 mov eax,dword ptr [edx+8] //这次传参是root.field3
007035E8 push eax
007035E9 call inorder (7011FEh)
007035EE add esp,0Ch
007035F1 pop edi
007035F2 pop esi
007035F3 pop ebx
007035F4 add esp,0C0h
007035FA cmp ebp,esp
007035FC call @ILT+335(__RTC_CheckEsp) (701154h)
00703601 mov esp,ebp
00703603 pop ebp
00703604 ret
分析
这次代码的分析还是不难的,流程很短也很清晰,刚好可以用来了解结构体和递归,算是初步认识一下。
下次会找一个比较难的带结构体的代码来分析
struct tmp{
DWORD val;
DWORD tmpAddr1;
DWORD tmpAddr2;
}
DWORD func1(root,returnSize){
void* res = malloc(DWORD*501);
int* returnSize = 0;
res = inorder(root,res,returnSize);
return res;
}
void inorder(root,res,returnSize){
if(root == 0) return;
inorder(root.field2,res,returnSize);
res[resSize] = root.field1;
*resSize = (*resSize)++;
inorder(root.field3,res,returnSize)
}
源代码
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
void inorder(struct TreeNode* root, int* res, int* resSize) {
if (!root) {
return;
}
inorder(root->left, res, resSize);
res[(*resSize)++] = root->val;
inorder(root->right, res, resSize);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int* res = (int*)malloc(sizeof(int) * 501);
*returnSize = 0;
inorder(root, res, returnSize);
return res;
}