:00436100 56 push esi ;esi入栈,因为esi要保存到后面要使用
:00436101 8BF1 mov esi, ecx ;esi=ecx
:00436103 8B4E08 mov ecx, dword ptr [esi+08];ecx=内存esi+08处
:00436106 85C9 test ecx, ecx ;测试ecx
:00436108 7419 je 00436123 ;为0则跳转到00436123处
:0043610A E821FCFEFF call 00425D30 ;调用425d30处函数
:0043610F 8B4E08 mov ecx, dword ptr [esi+08];ecx=esi+8
:00436112 85C9 test ecx, ecx ;测试ecx
:00436114 7406 je 0043611C ;为0跳转
:00436116 8B01 mov eax, dword ptr [ecx] ;ecx=内存ecx的值
:00436118 6A01 push 00000001 ;压栈(传一个参数)
:0043611A FF10 call dword ptr [eax] ;调用函数,函数地址在内存eax处
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436114(C)
|
:0043611C C7460800000000 mov [esi+08], 00000000 ;内存esi+08=0
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436108(C)
|
:00436123 8B0D34E09000 mov ecx, dword ptr [0090E034];ecx=内存90e034的值
:00436129 5E pop esi ;esi出栈
:0043612A E931371F00 jmp 00629860 ;跳转到629860
:0043612F 90 nop
* Referenced by a CALL at Address:
|:00435435
|
:00436130 6AFF push FFFFFFFF ;FFFFFFFF入栈
:00436132 684B758200 push 0082754B ;入栈
:00436137 64A100000000 mov eax, dword ptr fs:[00000000];eax=SEH链指针(NT_TIB结构第一项指向的EXCEPTION_REGISRATION结构的Prev(下一个结构的地址)
:0043613D 50 push eax ;SEH地址入栈
:0043613E 64892500000000 mov dword ptr fs:[00000000], esp;设置函数的当前的SEH链,链地址是82754b
:00436145 51 push ecx ;ecx入栈
:00436146 56 push esi ;esi入栈
:00436147 8BF1 mov esi, ecx ;esi=ecx
:00436149 57 push edi ;edi入栈
:0043614A 68440B0000 push 00000B44 ;b44入栈
:0043614F 8B4608 mov eax, dword ptr [esi+08] ;eax=esi+08
:00436152 8B781C mov edi, dword ptr [eax+1C] ;edi=eax+1c
:00436155 E816702B00 call 006ED170 ;函数006ed170
:0043615A 83C404 add esp, 00000004 ;丢弃一个堆栈值
:0043615D 89442408 mov dword ptr [esp+08], eax ;esp+8=eax
:00436161 85C0 test eax, eax ;测试eax是否为0
:00436163 C744241400000000 mov [esp+14], 00000000 ;esp+14=0
:0043616B 740A je 00436177 ;根据上面eax的测试结果来跳转
:0043616D 57 push edi ;edi入栈
:0043616E 8BC8 mov ecx, eax ;ecx=eax
:00436170 E8FB700200 call 0045D270 ;函数45d270
:00436175 EB02 jmp 00436179 ;跳转到436179
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0043616B(C)
|
:00436177 33C0 xor eax, eax ;根据上面的eax为0跳转到这 eax再次清0(其实这句可要可不要,因为eax已经是0了,可见程序员写的代码
还是有点重复)
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436175(U)
|
:00436179 894624 mov dword ptr [esi+24], eax ;关键地方:(这就是血的基址说明有以下2点 : 1.当eax为0时,就表示用户正在登录游戏,或者在选择人物
的时候. 用户的数据结构体当时还没有取到所以为0 2.就是用户已经正常登录了,用来不停的更新用户数据,比如当前血量、蓝值等.esi为基址再加上偏移24就查找到了内存某一块地方x, 其实x就是一个结构 定义了人物的各种属性 结构+偏移25ch就得到了当前用户结构,如:当前多少血量,反过来想的话就是用程序到此处去取结构体的地址,结构体的地址再加偏移就是具体的用户值
)
:0043617C 5F pop edi ;edi出栈
:0043617D 85C0 test eax, eax ;再次测试eax是否为0
:0043617F C7442410FFFFFFFF mov [esp+10], FFFFFFFF ;esp+10=ffffffff
:00436187 5E pop esi ;esi出栈
:00436188 7525 jne 004361AF ;如果eax不为0就跳转,如果eax为0就从下面去创建用户信息,,不为0就不需要创建了直接跳到4361af处
:0043618A 68AC030000 push 000003AC ;入栈
* Possible StringData Ref from Data Obj ->"CECGameRun::CreateHostPlayer"
|
:0043618F 6820648C00 push 008C6420 ;入栈
:00436194 6A02 push 00000002 ;入栈
:00436196 E8A5A90000 call 00440B40 ;函数
:0043619B 83C40C add esp, 0000000C ;丢弃一个4字节栈
:0043619E 32C0 xor al, al ;al=0 ,这个值是用作这个函数的返回值,值上级函数查询使用
:004361A0 8B4C2404 mov ecx, dword ptr [esp+04] ;ecx=esp+4
:004361A4 64890D00000000 mov dword ptr fs:[00000000], ecx;撒消SEH链
:004361AB 83C410 add esp, 00000010 ;还给堆栈4个字
:004361AE C3 ret ;函数返回
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00436188(C)
|
:004361AF 8B4C2404 mov ecx, dword ptr [esp+04] ;这里是用户已经登录的返回
:004361B3 B001 mov al, 01 ;al=1,这个值是用作这个函数的返回值,值上级函数查询使用
:004361B5 64890D00000000 mov dword ptr fs:[00000000], ecx;撒消SEH链
:004361BC 83C410 add esp, 00000010 ;还给堆栈4个字
:004361BF C3 ret ;函数返回
下面代码实现读取用户当前血量,重启游戏后还是能再次读取到。
.386
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
include hook.inc
includelib hook.lib
IDD_DIALOG1 equ 101
IDC_EDIT1 equ 1000
IDC_EDIT2 equ 1001
IDC_EDIT3 equ 1002
IDC_EDIT4 equ 1003
IDC_BUTTON1 equ 1004
IDC_STATIC equ -1
IDT_TIME equ 1
ELE_RAW EQU 02E0A424h
ELE_HP EQU 06E68270H
ELE_MP EQU 025CH
ELE_MAXHP EQU 06E68288H
ELE_MAXMP EQU 06E68284H
.data?
hInstance dword ?
hProcess dword ?;打开的进程
stMsg MSG <?>;消息结构
dwRaw dword ?
dwHp dword ?
dwMp dword ?
dwMaxHp dword ?
dwMaxMp dword ?
.data
szErr byte '游戏并没有启动,请先启动游戏!',0
szErr2 byte '权限不够,打开进程失败!',0
szTitle byte 'QElementClient Window',0
.code
_DiaProc proc uses ebx esi edi hWnd,uMsg,wParam,lParam
local @ProcessId
mov eax,uMsg
.if eax==WM_COMMAND
mov eax,wParam
.if ax==IDC_BUTTON1
invoke _msg
.endif
.elseif eax==WM_TIMER
invoke ReadProcessMemory,hProcess,ELE_RAW,addr dwRaw,4,NULL
add dwRaw,ELE_MP
invoke ReadProcessMemory,hProcess,dwRaw,addr dwMp,4,NULL
invoke SetDlgItemInt,hWnd,IDC_EDIT1,dwMp,FALSE
.elseif eax==WM_CLOSE
invoke UninstallHook
invoke DestroyWindow,hWnd
invoke PostQuitMessage,-1
.elseif eax==WM_INITDIALOG
invoke SetTimer,hWnd,IDT_TIME,1000,NULL
invoke FindWindow,addr szTitle,NULL
mov ebx,eax
invoke GetWindowThreadProcessId,ebx,addr @ProcessId
invoke OpenProcess,PROCESS_VM_OPERATION OR PROCESS_VM_READ OR PROCESS_VM_WRITE OR PROCESS_CREATE_THREAD,NULL,@ProcessId
.if eax
mov hProcess,eax
.else
invoke MessageBox,NULL,addr szErr2,0,MB_OK
.endif
invoke InstallHook,hWnd
.else
mov eax,FALSE
RET
.endif
mov eax,TRUE
RET
_DiaProc endp
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke FindWindow,addr szTitle,NULL
.if eax
invoke CreateDialogParam,hInstance,IDD_DIALOG1,eax,addr _DiaProc,NULL
invoke ShowWindow,eax,SW_SHOW
.while TRUE
invoke GetMessage,addr stMsg,NULL,0,0
.break .if !eax
invoke TranslateMessage,addr stMsg
invoke DispatchMessage,addr stMsg
.endw
.else
invoke MessageBox,NULL,addr szErr,0,MB_OK
.endif
invoke ExitProcess,-1
end start
第一次做这样的工作,如有任何不足之处请见凉.(本章只是学习,就不具体指出是哪个游戏)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课