逆向分析练习四(二叉树的中序遍历)

逆向分析练习四(二叉树的中序遍历)

今天这个题目中包含了递归和结构体,可以充分了解到结构体在内存中的展现形式

题目描述

中序遍历

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用C++求二叉树的结果并打印可以使用递归方法实现,具体步骤如下: 1. 如果当前结点为空,返回。 2. 递归遍左子树。 3. 输出当前结点。 4. 递归遍右子树。 的最后一个结点即为二叉树的最右下角结点,可以在递归遍时记录最后一个结点。 的第n个结点可以在递归遍时使用一个计数器来记录当前是第几个结点,并在遍到第n个结点时输出。 以下是示例代码: ```c++ #include <iostream> using namespace std; // 二叉树结点定义 struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; void inorderTraversal(TreeNode* root) { if (root == NULL) { return; } inorderTraversal(root->left); cout << root->val << " "; inorderTraversal(root->right); } TreeNode* getInorderLastNode(TreeNode* root) { if (root == NULL) { return NULL; } while (root->right != NULL) { root = root->right; } return root; } int getInorderNthNode(TreeNode* root, int n, int& count) { if (root == NULL) { return -1; } int res = getInorderNthNode(root->left, n, count); if (count == n) { return root->val; } count++; if (res != -1) { return res; } return getInorderNthNode(root->right, n, count); } int main() { // 构建一个二叉树 TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(3); root->left->left = new TreeNode(4); root->left->right = new TreeNode(5); // inorderTraversal(root); cout << endl; // 的最后一个结点 TreeNode* lastNode = getInorderLastNode(root); cout << lastNode->val << endl; // 的第n个结点 int n = 3; int count = 1; int nthNode = getInorderNthNode(root, n, count); cout << nthNode << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值