零基础学化妆好学吗,零基础自学化妆
本内容首先介绍从目标程序中获取怪物信息的方法。
该内容的markdown包含文章最后一个链接中的代码和文件。
获取怪物信息
0x01:工具和背景知识
1 .作弊引擎
Ce可以检查内存工件并进行调试。
2.国际开发协会
用于反汇编静态代码。
3 .免疫调试器
查看和调试代码非常有用。
4.语言(C,python,lua,汇编))。
c:用来写辅助程序。
Python:用于在免疫调试器中创建插件
Lua:用于在ce上创建插件
组件:要是我能理解就好了。你不需要写。你需要颠倒程序逻辑。
0x02:找到修改血量代码的地方。
先找到怪物血量的地址。如下图所示。
如上图所示,按照上图,右键点击‘什么覆盖了这个位置’这个位置,点击【添加到流程】。
加入过程后,攻击这个怪物。此时,可以看到下图。
图中地址00570FFB是修正怪物血量的代码位置。
0x03:找到调用堆栈
你还记得你最后一次使用ce lua吗?
编写一个类似如下的脚本
code:$(root)/info/find _ HP _ base . Lua
函数打印堆栈(ebp,Deep)-打印堆栈的函数,调用进程如果deep==0则返回 end local ebp _ 4=readinteger ebp _ 4)local next _ ebp=readinteger(ebp)str _ ret=str _ ret . print _ stack)next _ ebp对于返回值堆栈,Deep-1)返回str _ retendfunctionclear _ debug(-clear所有添加的断点local TBL=debug _ getbreakpointlist)如果tbl==,I, v))debug _ remove breakpoint(v)endedfunctiondebugger _ on breakpoint))-默认断点函数if EIP==0x 570 FFB-这个断点函数修正了刚刚获得的怪物血量的代码位置。 thenlocalret=print _ stack(ebp 10)print(ret)else print(未找到))End Return 1 End Clear _ Debu Debu Bund我们现在在CFB,上面的代码。
玩家攻击后,打印如下图所示。
上图红色方框中的指纹是抽血呼叫的过程。我们拿这个去找基本地址吧。
7E76A-70fa 54-747 e0e-87c 579-86052 b-75b 247 a-75b 0444 b-75b 041 e 0-8602 C6-0x 04:查找基址现在免疫调试
从上面图1的位置(0x570FFB)来看,血容量应该保持在esi0xf4的位置,但是esi的值呢?我们现在就去找吧。
我们正在网上寻找图2中的位置(0x570ff2)。ESI是从eax分配的,那么eax是怎么来的呢?
在网上看到图3,有一个函数调用。一般来说,组装好的函数保存在eax中(如果有返回值的话)。所以,我们来跟进一下这个功能到底有没有回来。
上图是进入函数0x715720后的相关内容。试着翻译一下上面的内容。下面是翻译过来的二维码。
EAX=(ecx0x 30);eax=(eax;EDX=(ebp0x 8);while(1):)ecx=)eax0x 10);//MOV ECX,dwordptrds:[eax 10]if(ecx EDX){//CMP ECX,EDX;jeshortwarspear . 0071573 ceax=(eax0x 4);继续;} else if(EXCEDX)//jnbshortwarspear . 0071574 beax=(eax0x 8);继续;} else { EAX=*(eax0x 14);布莱克;有c/c语言基础的朋友很容易理解,上面的代码就是数据结构二叉树的查找过程。所以,这是真的。
这个游戏的怪物信息是用二叉树存储的。把上图中的eax想象成一个节点。那么eax0x10的位置可以存储类似于id的值。然后与edx的目标值进行比较。如果当前id edx是右节点(eax0x04),如果当前id edx是左节点(eax0x08),如果相等,则使用eax=*(eax0x14) Then。所以我们从上面的汇编代码中得到了三条信息:1.a确实是返回值。2.怪物信息存在于二叉树中。3.从第一行(MOVEAX,DWORD PTR DS:[ecx 38]),我们可以看到我们的下一个跟踪目标是这个ecx。如果继续按照上面组装图的4,5,6,会发现找到了基址(哈哈,很尴尬,之前的视图栈好像没用。没关系。下次一定会用。因为之前写完已经很久了,所以边做边写这篇文章。所以没想到没用。)从‘MOV EAX,获取dwptrds中的基址0x 9a 45 b 0 # #0x 05:[9a 45 b 0]’:测试基址是否正确。我们编写下面的lua代码位置:$(root)/info/print _ tree . Lua ` `` ` Lua函数句柄node (value,ptr,hp) print(string.format(%x,%x,%d ,value,ptr,hp)) end函数read_tree(node,C)-read代码if (node==0或node==nil)然后返回end local left=read integer(node 4)local right=read integer(node 8)local value=read integer(node0x 10)local ptr=read integer它对应于上述汇编代码中的(esi f4)。read_tree(left,func) read_tree(right,func) func(value,ptr,HP)end Local g _ base=read integer(0x 9a 45 b 0)Local tmp _ ptr=read integer(g _ base0x 10)tmp _ ptr=read integer(tmp _ ptr0x 38)Local=read integer(tmp _ ptr)read _ tree(root,handle node)将上面的代码放在ce中执行,会看到下面的打印
我已经在上面的图1中打印了我自己的hp。可见这个基址是没有问题的。
0x06:编写我们的辅助程序
好了,现在我们已经有了我们需要的一切,让我们开始写我们的辅助程序。
如图,用vs2019打开项目后的目录结构。
图中位置1的项目与辅助逻辑有关,如查看怪物信息、攻击怪物、拾取物品等。最终生成一个静态库。
图中位置2的项目是注入后的主流程,最后编译成动态库。(其实1和2是可以合并在一起的,因为2在运行时调用了gameData项目中的接口,所以gameData是静态链接到2中的。)
这个项目用来把上面写的动态库注入到目标程序中。
让我们解释一下本章中用到的一些重要代码。
1.灌浆法
代码位置:$(根)/injectdll/injectdll.cpp
war handle=FindWindowA(GAME _ CLASS _ NAME,NULL);//根据窗口名称查找目标进程的窗口句柄if(war handle==0)return;printf(查找句柄 n );GetWindowThreadProcessId(warHandle,PID);//根据目标句柄获取目标主进程PID if(PID==0){ printf( Get PID error n );返回;} h PROCESS=open PROCESS(PROCESS _ ALL _ ACCESS,FALSE,PID);//获取目标进程句柄,获取所有操作权限if(h process==null){ printf( geth process error n );返回;} address dw=(lpd word)VirtualAllocEx(h process,NULL,256,MEM _提交,页面_读写);//在目标进程中申请一段内存,主要用来存放我们要注入的动态库的完整路径if(addresdw==null){ printf( geth process error n );返回;} WriteProcessMemory(hProcess,addressDW,dllPath,strlen(dllPath) 1,by write size);//将动态库的完整路径保存到刚刚申请的内存中if(by write size strlen(dll path)){ printf(写内存失败!);返回;} thread handle=CreateRemoteThread(h process,NULL,NULL,(LPTHREAD _ START _ ROUTINE)loadlibrary a,addressDW,NULL,NULL);//在目标进程中创建一个线程,线程会执行加载动态库waitforsingleobject(thread handle,0xffffffff)的操作;//等待刚刚加载动态库的操作完成。好了,这里,我们的注射操作完成了。close handle(thread handle);VirtualFreeEx(hProcess,addressDW,256,MEM _提交);close handle(h process);### 2.注入后主函数代码的位置:$(root)/gamedata/hookgamemainthread . CPP ``` c LRESULT回调游戏WndProc (intncode,WParam WParam,LPARAM LPARAM){ cwpstruct * lparg=(cwpstruct *)LPARAM;if(ncode==HC _ action){ if(lparg-hwnd==getgamewnhandler()lparg-message==g _ mymsgcode){//注入的ui线程会向主线程发送消息,消息会在这里被钩子截获。拦截后,将根据消息类型执行相关操作do action((msg action)lparg-)。返回1;} } return CallNextHookEx(g _ hhk game,nCode,wParam,lParam);} DWORD HookMainThread() //注入的main函数实际上会实例化一个ui窗口,然后在窗口的主进程中执行这个函数{ log _ debug( hook ok n );HWND hGame=getGameWndHandle();//获取主线程窗口句柄。这是基址dword nd threadid=getwindowthreadprocessid(hgame,null)通过ce实现找到主线程句柄;//根据主线程句柄获取主线程ID if(ndthreadID==null { return 1;} g _ hhk game=SetWindowsHookExA(WH _ CALLWNDPROC,GameWndProc,NULL,ndThreadId);//在主线程中注册一个钩子函数,钩子函数是上面的GameWndProc return 1;}最终效果如下图所示:
如您所见,还有一个窗口,其图标与我们的目标进程相同,名称是Dialog。这是注入的UI线程。
单击窗口中的test按钮,将向主线程发送一条MsgTest消息。主线程收到消息后会将怪物信息输出到e:shlogwarspear.log(这个位置写死了,可以在GameData/debug.h文件中修改)
如您所见,日志输出与我们在ce中看到的一样。在这一点上,我们获得怪物信息是可以的。
如果你有什么不明白的,请向我提出问题。
这篇文章的降价在下面的链接中,请下载并交流。
https://www.dslt.tech/article-49-1.html
版权声明:本文由侯善立原创。欢迎分享这篇文章。转载请保留出处。