C++逆向分析移除链表元素实现方法详解
目录
- 前言
- 题目描述
- debug版汇编代码
- 分析
- 源代码
前言
这次的题目可以练习到循环加结构体数组和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; }
到此这篇关于C++逆向分析移除链表元素实现方法详解的文章就介绍到这了,更多相关C++移除链表元素内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!