C++逆向分析移除链表元素实现方法详解
ch132 人气:0前言
这次的题目可以练习到循环加结构体数组和ifelse的大量嵌套。
逆向这种东西就是一个经验的积累,做得多了就会有感觉,这次的分析我会详细写一下如何判断哪里是if哪里是while这种逻辑判断。
题目描述
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
debug版汇编代码
004E3580 push ebp
004E3581 mov ebp,esp
004E3583 sub esp,0D8h
004E3589 push ebx
004E358A push esi
004E358B push edi
004E358C lea edi,[ebp-0D8h]
004E3592 mov ecx,36h
004E3597 mov eax,0CCCCCCCCh
004E359C rep stos dword ptr es:[edi] //下面是业务代码
004E359E mov eax,dword ptr [head]
004E35A1 mov dword ptr [cur],eax //cur = head;
004E35A4 mov dword ptr [prev],0 //prev = 0;
004E35AB cmp dword ptr [cur],0 //cur != 0,这里可以看出来应该是一个while或者if
004E35AF je removeElements+0A8h (4E3628h) //跳出while
004E35B1 mov eax,dword ptr [cur]
004E35B4 mov ecx,dword ptr [eax] //熟悉的取指针的内容
004E35B6 cmp ecx,dword ptr [val] //这是判断if(cur.filed1 == val)
004E35B9 jne removeElements+97h (4E3617h) //跳到else
004E35BB mov eax,dword ptr [cur]
004E35BE cmp eax,dword ptr [head] //if(cur==head),同上这又是个ifelse
004E35C1 jne removeElements+6Ah (4E35EAh)
004E35C3 mov eax,dword ptr [cur]
004E35C6 mov ecx,dword ptr [eax+4] //ecx = cur->field2
004E35C9 mov dword ptr [head],ecx //head = cur->field2
004E35CC mov esi,esp
004E35CE mov eax,dword ptr [cur]
004E35D1 push eax
004E35D2 call dword ptr [__imp__free (4E834Ch)] //这里应该是调用了free
004E35D8 add esp,4
004E35DB cmp esi,esp
004E35DD call @ILT+335(__RTC_CheckEsp) (4E1154h)
004E35E2 mov eax,dword ptr [head] //eax = head
004E35E5 mov dword ptr [cur],eax //cur = head
004E35E8 jmp removeElements+95h (4E3615h)
004E35EA mov eax,dword ptr [prev] //这里是else
004E35ED mov ecx,dword ptr [cur] //ecx = cur,eax = prev
004E35F0 mov edx,dword ptr [ecx+4] //edx = cur.field2
004E35F3 mov dword ptr [eax+4],edx //prev.field2 = cur.field2
004E35F6 mov esi,esp
004E35F8 mov eax,dword ptr [cur]
004E35FB push eax
004E35FC call dword ptr [__imp__free (4E834Ch)] //这里应该是调用了free
004E3602 add esp,4
004E3605 cmp esi,esp
004E3607 call @ILT+335(__RTC_CheckEsp) (4E1154h)
004E360C mov eax,dword ptr [prev]
004E360F mov ecx,dword ptr [eax+4]
004E3612 mov dword ptr [cur],ecx //cur = prev->field2
004E3615 jmp removeElements+0A6h (4E3626h) //从这里可以看出来是一个if~else
004E3617 mov eax,dword ptr [cur]
004E361A mov dword ptr [prev],eax //prev = cur
004E361D mov eax,dword ptr [cur]
004E3620 mov ecx,dword ptr [eax+4] //cur.field2
004E3623 mov dword ptr [cur],ecx /cur = cur.filed2
004E3626 jmp removeElements+2Bh (4E35ABh) //这里是while的结尾
004E3628 mov eax,dword ptr [head] //出了while
004E362B pop edi
004E362C pop esi
004E362D pop ebx
004E362E add esp,0D8h
004E3634 cmp ebp,esp
004E3636 call @ILT+335(__RTC_CheckEsp) (4E1154h)
004E363B mov esp,ebp
004E363D pop ebp
004E363E ret
分析
- 根据004E35AB行代码可以看出这里是一个if或者while
- 再看他跳到的004E3628的上一行是跳回到判断所以可以判断这一个大while
- 一步一步看下去会看到004E35B6这一行发现是一个if判断再看一下他判断失败时跳的位置
- 失败会跳到004E3617看他的上一行代码004E3615 jmp removeElements+0A6h (4E3626h)
- 可以看出来判断就跳到下面的代码!=就顺序执行然后跳过的代码并出循环
- 继续看汇编代码会看到好几个这样的if~else
struct tmp{ DWORD val; DWORD tmpAddr; }; struct tmp* func(DWORD head,DWORD val) { cur = head; prev = 0; while(cur != 0){ if(cur->filed1 == val){ if(cur==head){ head = cur->field2; free(cur); cur = head; }else{ prev->field2 = cur->field2; free(cur); cur = prev->field2; } }else{ prev = cur; cur = cur->field2; } } return head; }
源代码
* struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeElements(struct ListNode* head, int val){ struct ListNode* cur = head, *prev = NULL; while(cur){ if(cur->val == val){ //头删 if(cur == head){ head = cur->next;//更新头结点 free(cur);//释放存放val的节点 cur = head;//更新当前节点 } //中间删 else{ prev->next = cur->next;//链接 free(cur);//释放当前为val的节点 cur = prev->next;//更新当前节点 } } //不是val就往后遍历 else{ prev = cur; cur = cur->next; } } return head; }
加载全部内容