瑞客论坛 www.ruike1.com
011-C
C+xdbg条件断点
修改遍历代码【瑞客论坛
www.ruike1.com】
011
xdbg
条件
011-C,C++xdbg条件断点,修改遍历代码
2021在线班
郁金香灬老师 QQ 150330575
交流群:158280115
学习目标:
调试器条件断点
链表指针偏移测试
修改遍历代码
对象
+0x20 对象指针
+0x28 对象指针? <二叉树>
+0x30 ID1
+0x34 ID2
[[怪对象+964]+5c] //怪物名字
[[[fs:[2C]+0]+8]+1C]=2C1DDFF0
[[[2C1DDFF0+2*0C+8]+964]+5C]
#include"pch.h"
/*
对象
+0x20 链表指针
+0x30 ID1
+0x34 ID2
[[怪对象+964]+5c] //怪物名字
[[[fs:[2C]+0]+8]+1C]=2C1DDFF0
[2C1DDFF0+下标*0x0C+8]
+964]+5C] //怪对象名字
*/
// [[[fs:[2C]+0]+8]+1C]=2C1DDFF0
int 遍历计数 = 0;
DWORD R4(UINT_PTR 地址)
{
__try
{
return *(DWORD*)地址;//ReadProcessMemory
}
__except (1)
{
return 0;
}
}
UINT_PTR 怪物数组地址()
{
//读取 [[[fs:[2C]+0]+8]+1C]
DWORD fs2C = 0;
__asm
{
mov eax,dword ptr fs:[0x2C]
mov fs2C,eax
}
DWORD 数组地址 = R4(R4(R4(fs2C + 0) + 8) +0x1C);
return 数组地址;
}
//[[[fs:[2c]+0]+8]+24] ==0x1F
DWORD 怪物数组结点数量()
{
//读取 [[[fs:[2C]+0]+8]+24]
DWORD fs2C = 0;
__asm
{
mov eax, dword ptr fs : [0x2C]
mov fs2C, eax
}
DWORD 数量 = R4(R4(R4(fs2C + 0) + 8) + 0x24);
return 数量;
}
// 获取结点对象 [2C1DDFF0+下标*0x0C+8]
UINT_PTR 获取结点对象(int 下标) //0..31 0..1F
{
// [怪物数组地址+下标*0x0C+8]
UINT_PTR 怪物地址 = 怪物数组地址();//[[[fs:[2C]+0]+8]+1C]
return R4(怪物地址 + 下标 * 0x0C + 8);
}
//打印怪物对象信息
void 打印怪物对象信息(UINT_PTR 对象)
{
UINT32 vftable = R4(对象 + 0);
if (vftable == 0) return; //如果对象是 空对象 直接返回
遍历计数 = 遍历计数 + 1;
UINT32 ID1 = R4(对象 + 0x30);
UINT32 ID2 = R4(对象 + 0x34);
//[[怪对象+964]+5c] //怪物名字
char* utf8怪物名字 =(char*)R4( R4(对象 + 0x964) + 0x5C);
if(utf8怪物名字==NULL) return; //如果对象是 空对象 直接返回
char 多字节怪物名字[256] = { 0 };
utf8ToAscii(utf8怪物名字, 多字节怪物名字);
printf("首对象信息 vftable=%X ID1=%X ID2=%X 名字=%s\n", vftable,ID1,ID2, 多字节怪物名字);
}
void 结点信息(UINT_PTR 对象)
{
UINT32 vftable = R4(对象 + 0);
if (vftable == 0) return; //如果对象是 空对象 直接返回
UINT32 ID1 = R4(对象 + 0x30);
UINT32 ID2 = R4(对象 + 0x34);
//[[怪对象+964]+5c] //怪物名字
char* utf8怪物名字 = (char*)R4(R4(对象 + 0x964) + 0x5C);
if (utf8怪物名字 == NULL) return; //如果对象是 空对象 直接返回
char 多字节怪物名字[256] = { 0 };
utf8ToAscii(utf8怪物名字, 多字节怪物名字);
printf("结点信息 vftable=%X ID1=%X ID2=%X 名字=%s\n", vftable, ID1, ID2, 多字节怪物名字);
}
//遍历链表
void 遍历链表(UINT_PTR 怪物对象首结点)
{
/*
对象
+0x20 链表指针
+0x30 ID1
+0x34 ID2
*/
BOOL 是偶数 = (怪物对象首结点 % 2 ==0);
UINT_PTR 对象 = R4(怪物对象首结点 + 0x20);
while (对象 && 是偶数)
{
//打印此结点信息
结点信息(对象);
//访问下一个结点对象
对象 = R4(对象 + 0x20);
是偶数 = (怪物对象首结点 % 2==0);
}
return;
}
//遍历数组
void 遍历对象数组()
{
//0..1F 0..怪物数组结点数量()
int 数量 = 怪物数组结点数量();
printf("遍历对象数组 数量=%d\n", 数量);
for (int i = 0; i < 数量; i++)
{
UINT_PTR 怪物对象首结点=获取结点对象(i);
打印怪物对象信息(怪物对象首结点);
遍历链表(怪物对象首结点);
}
}
VOID CALLBACK 主线_遍历对象数组(HWND h, UINT arg2, UINT_PTR arg3_id, DWORD time)
{
遍历计数 = 0;
KillTimer(h, arg3_id);
遍历对象数组();
}
004D4BAE | CC | int3 |
004D4BAF | CC | int3 |
004D4BB0 | 55 | push ebp |
004D4BB1 | 8BEC | mov ebp,esp | ecx=[[fs:[2c]+0]+8]
004D4BB3 | 8B41 24 | mov eax,dword ptr ds:[ecx+24] | eax=[ecx+24]=[[[fs:[2c]+0]+8]+24]
004D4BB6 | 83F8 FF | cmp eax,FFFFFFFF |
004D4BB9 | 75 06 | jne wow.4D4BC1 |
004D4BBB | 33C0 | xor eax,eax |
004D4BBD | 5D | pop ebp |
004D4BBE | C2 0800 | ret 8 |
004D4BC1 | 8B51 1C | mov edx,dword ptr ds:[ecx+1C] | edx=[[[fs:[2c]+0]+8]+1c]
004D4BC4 | 56 | push esi |
004D4BC5 | 8B75 08 | mov esi,dword ptr ss:[ebp+8] | 参数1
004D4BC8 | 23C6 | and eax,esi | 31数组上限=0x1F
004D4BCA | 8D0440 | lea eax,dword ptr ds:[eax+eax*2] | eax=eax*3
004D4BCD | 8D4482 04 | lea eax,dword ptr ds:[edx+eax*4+4] | eax=edx+4+参数1*0x0C //12=0x0C
004D4BD1 | 8B40 04 | mov eax,dword ptr ds:[eax+4] | eax=[edx+4+参数1*0x0C+4]
004D4BD4 | A8 01 | test al,1 | eax=[edx+8+参数1*0x0C]
004D4BD6 | 75 04 | jne wow.004D4BDC | [[[fs:[2c]+0]+8]+1c]+8+0*0C //可能是怪物数组
004D4BD8 | 85C0 | test eax,eax | [[[2C1DDFF0+下标*0C+8]+964]+5C] //0..31//0..0x1F
004D4BDA | 75 02 | jne wow.004D4BDE | eax=[[[2C1DDFF0+00*0C+8]+964]+5C] //对象
004D4BDC | 33C0 | xor eax,eax | eax=0
004D4BDE | 57 | push edi |
004D4BDF | 8B7D 0C | mov edi,dword ptr ss:[ebp+C] | 参数2
004D4BE2 | 53 | push ebx |
004D4BE3 | A8 01 | test al,1 | 循环开始 11111101 and 1 =1
004D4BE5 | 75 2F | jne wow.004D4C16 | 判断eax是否是单数 //奇数 哪果eax是单数则跳出循环
004D4BE7 | 85C0 | test eax,eax |
004D4BE9 | 74 2B | je wow.004D4C16 | 判断eax==0则退出循环
004D4BEB | 3970 18 | cmp dword ptr ds:[eax+18],esi | [对象+18]与 参数1比较
004D4BEE | 75 0F | jne wow.004D4BFF |
004D4BF0 | 8B50 30 | mov edx,dword ptr ds:[eax+30] | [对象+30] 与 ID1 比较
004D4BF3 | 3B17 | cmp edx,dword ptr ds:[edi] |
004D4BF5 | 75 08 | jne wow.004D4BFF | 不相等 进入下一次循环
004D4BF7 | 8B50 34 | mov edx,dword ptr ds:[eax+34] | [对象+30] 与ID1 比较 相等走到这里
004D4BFA | 3B57 04 | cmp edx,dword ptr ds:[edi+4] |
004D4BFD | 74 19 | je wow.004D4C18 | [对象+30] [对象+34] 与ID1,ID2分别比较 如果相等 则返回对象
004D4BFF | 8B59 1C | mov ebx,dword ptr ds:[ecx+1C] | 下一次循环
004D4C02 | 8BD6 | mov edx,esi | edx=0C,1D
004D4C04 | 2351 24 | and edx,dword ptr ds:[ecx+24] | [ecx+24]=1F // edx=edx and 1F
004D4C07 | 8D1452 | lea edx,dword ptr ds:[edx+edx*2] | edx=edx*3
004D4C0A | 8D1493 | lea edx,dword ptr ds:[ebx+edx*4] | edx=ebx+下标2*0x0C
004D4C0D | 8B12 | mov edx,dword ptr ds:[edx] | edx=[edx]=[ebx+下标2*0x0C]
004D4C0F | 03D0 | add edx,eax | edx=1C+对象
004D4C11 | 8B42 04 | mov eax,dword ptr ds:[edx+4] | 对象=[1C+对象+4]=[对象+1C+4]=[对象+0x20]
004D4C14 | EB CD | jmp wow.004D4BE3 | 循环结束
004D4C16 | 33C0 | xor eax,eax | eax=NULL //eax=0
004D4C18 | 5B | pop ebx | 返回值 eax
004D4C19 | 5F | pop edi |
004D4C1A | 5E | pop esi | 角色对象,怪物对象,其它对象?
004D4C1B | 5D | pop ebp | 2C318C50 角色对象
004D4C1C | C2 0800 | ret 8 | [eax+D0]+174
004D4C1F | CC | int3 | [2CFD05C8+D0]+174
004D4C20 | 56 | push esi |
004D4BFF | 8B59 1C | mov ebx,dword ptr ds:[ecx+1C] | 下一次循环
004D4C02 | 8BD6 | mov edx,esi | edx=0C,1D
004D4C04 | 2351 24 | and edx,dword ptr ds:[ecx+24] | [ecx+24]=1F // edx=edx and 1F
004D4C07 | 8D1452 | lea edx,dword ptr ds:[edx+edx*2] | edx=edx*3
004D4C0A | 8D1493 | lea edx,dword ptr ds:[ebx+edx*4] | edx=ebx+下标2*0x0C
004D4C0D | 8B12 | mov edx,dword ptr ds:[edx] | edx=[edx]=[ebx+下标2*0x0C]
004D4C0F | 03D0 | add edx,eax | edx=1C+eax
004D4C11 | 8B42 04 | mov eax,dword ptr ds:[edx+4] eax=1C+eax+4
mov eax, dword ptr ds:[eax+0x20]