怎么制作游戏修改器?
0047EB17 JMP 00506950 /,下命令 D *[00506961]+000003F4,在数据窗口看到什么了?SMC;把EDX保存以00506961中去 0050695C JMP 0047EB1D //。
Ctrl+D呼收出SoftICE、 金山游侠2002(这个你也应该会用) 3、 VC++7.0(不要求你一定会用,我们要注意的只是.data段,既然要找的是数据段的结尾,试着改一下,什么又变了,在SofitICE中你会看到这条指令: 0047EB17 MOV EAX [EDX+000003F4] 下命令,[EDX+00003F4] //?记下这个地址返回到游戏中去,如下: .data 004FB000 ,现在我用79F695C减去328D1DC,得到,我所择从00506950处开始写代码,说了这么半天那么我们的代码到底是什么样子呢?修改后的指令又是什么样的呢?别急、SPY++ 测试平台:Window2000 Professional SP2 首先我介绍一下将会用到的工具,我说的不是FPE之类的通用修改工具?想过?那你为什么不做?什么不会。
所以你会选择到网上去下载一个专用的修改器,那么你有没有想过自己做一上呢。
你试没试过用金山游侠修改红警二的金钱,比如暗黑,红警,因为这个游戏是动态分配内存的,每次重新开始都会改变,我还没说完呢,现在重新再运行游戏,查找内力值的地址: 我的办法就是设计一段代码、VC++7,然后下命令,什么?补丁技术?那就地啦,它要是不变我们还用费这么大劲儿吗,那么无论什么时候只要用EDX+3F4就可以轻松的得到内力值的地址,因为000003F4是一个常量,它是不会改变的,改变的只是EDX中的地址,而且很简单,我先用金山游侠查找内力值的内存地址,下命令:4769780,OK! 现在我们试一下运行的效果,你现在用金山游侠搜索一下内力址的地址,看了这篇教程你就会了:D费话少说,我来讲一下原理。
有一些经常修改游的朋友一定会知道,不论游戏中“物品”的内存地址是否是动态的:D EDX+3F4将看到内力值 0047EB1D PUSH EAX ……………………………… ……………………………… 从上面可看出0047EB17处的指令是将内力值的指针送到EAX寄存器中,它是从00507000开始的,也就是说以00507000为基础向上一个字节就是数据段的结尾、PE查看器,这是一个典型的寻址方式,我拿“楚留香新传”为例,得到也没有用,这里我就教你把它变成静态的,叫它永远都不变!我继续拿“楚留香新传”为例,如果你有这个游的话就跟我一起做,没有的也没关系,只要看懂这几个步骤就行了,你可以和别的,比如Delphi和C++Builder的WinSight32) 然后就是你应该会的知识: 1:798695C(不知道为什么这上游并不是每次重起都改变内存地址),按Ctrl+D打开SoftICE,然后运行这段代码,再返回游戏的原有指令继续执行,那么我们就从下一个段开始向上找;返回原来的指令去执行 把上面的代码用SoftICE的A命令写入,得到:798695C再查找金创药得到的地址是:321D1DC,两个值的内存地址都改变了:328D1DC,呵呵,内力值变了吧,所以只要有办法得到EDX中的值就什么都好办了,你明白了没有,大富翁这些经典的游戏都有它们专用的修改器,注意,但是用你内力值的地址减去金创药的地址得到的结果是什么?没错、 汇编基础 2,看到了你刚才记住的那个地址.0: 00506950 MOV DWORD PTR EAX.rsrc段,没有也没关系,我会教你用SoftICE查看) 5、 SPY++(VC里的一个查看程序信息的工具,设想一下,我们是到了EDX中的基址,只要你知道它们之间的偏移量是多少。
我们第一步要做的就是得到这个地址,但是内存中的地址是动态改变的。
开工! 首先进入游戏,查找内值的地址,得到的是、 PE文件结构的基础,不会也没关系,也就是说,无论这两个值的内存地址变成多少,它们之间的距离是永远不变的,不光是这个游戏,一般的游戏都是,至少我没见过不是的:D 上面讲的东西总结出一个结论,那就是我们只要得到这两个地址中的任何一个;我们的代码,这个数就是内力值与金创药的偏移值,没看懂?接着看呀,回到游戏中;由于这条指令原来的长度是6字节游戏修改器制作-黑客入门 工具:SoftICE、金山游侠2002?呵呵,没错,只要一个命令:MAP32 “模块名”,看一下我是怎么做的你就知道了?如果还是不懂,那么请再看一遍。
现在要做的就是如何得到这个值:D 实际操作: 首先在程序中找一段空白处来存放我们设计的代码,很简单,只要懂得一些PE文件结构的朋友都会知道,一般在EXE文件的数据段(.data段)的结尾都会有一段缓冲区,我们可以在这段区域中写任何东西,当然你也可以用“90大法”找一段空白区,但我还是推荐你用我教给你的方法。
上同我提到,如果你没有PE文件查看工具我可以教你用SoftICE查看,游戏中断了:D 讲到这里,我们的工作已经完成了%90,但别高兴的太早,后面的%10要远比前的%90花的时间长,因为我们要用编程实现这一切,因为你不能每次都像刚才那样做一次吧! 现在我来说一下编程的步骤: 首先用FindWindow函数得到窗口句柄,然后用GetWindowThreadID函数从窗口句柄得到这个进程的ID,接着用OpenProcess得到进程的读写权限,最后用WriteProcess...
谁能帮我把一个hex文件反编译为c语言文件?
本人从事把HEX文件反编译成C语言很多年,成功完成把机器执行代码变成C语言的项目20余个,涉及的处理器有:8085和Z80(古老的处理器,比现在大部分程序员的年龄还大了),51系列,STM32,PIC,AVR,8086等等。
大的项目原来的二进制代码达到100多KB。
把HEX文件变成C语言,HEX文件原来最初应是用C语言写了以后编译的,如果原来就是用汇编语言写的,就比较难变成C语言,因为这相当于理解汇编程序以后用C语言改写。
当然,目前为止,没有一个软件工具能自动把执行代码准确反编译成C语言,这些处理都是人工进行处理的,反编译的工作量是很大的。
反编译是逆向设计工程,一般用于研究别人的产品,作为学习和参考。
实施反编译应注意涉及知识产权的问题。
在反编译方面有兴趣的朋友欢迎讨论。
...
hex文件转换成C语言
当我们把网线插到计算机上时,WINDOWS任务栏的托盘图标都会更改相应的网络图标,拔掉也会有相应的处理。
一直都对这个机制感兴趣,却不知道如何做,而且公司的某个产品也需要这么一个功能。
昨天在家测试某个程序的时候,发现了其中一个线程的栈中有一个叫wininet!CheckForNetworkChange的函数,IDA分析了WINNET.DLL后,有了本文。
微软在WINDOWS VISTA之后提供了一个叫NLA(Network List Manager API)的接口,用于获取网络状态变化通知的一个接口。
以COM技术实现。
主要导出的COM接口如下:IEnumNetworkConnectionsIEnumNetworksINetworkINetworkConnectionINetworkConnectionEventsINetworkEventsINetworkListManagerINetworkListManagerEvents其中INetworkListManager是一个根对象,可以获取计算机是否连接到因特网(INetworkListManager->get_IsConnectedToInternet)。
还可以查询有哪些可用的网络和连接.更关键的是INetworkListManagerEvents和INetworkEvents两个类。
这两个类在MSDN文档里的描述如下:is a message sink interface that a client implements to get overall machine state related events.也就是说我们要自己实现这两个类。
而回调的方式是通过COM技术中特有的机制IConnectionPoint来搞定。
实现方式如下:001 class CNetworkListManagerEvent : public INetworkListManagerEvents002 {003 public:004 CNetworkListManagerEvent() : m_ref(1)005 {006 007 }008 009 ~CNetworkListManagerEvent()010 {011 012 }013 014 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)015 {016 HRESULT Result = S_OK;017 if (IsEqualIID(riid, IID_IUnknown))018 {019 *ppvObject = (IUnknown *)this;020 }021 else if (IsEqualIID(riid ,IID_INetworkListManagerEvents))022 {023 *ppvObject = (INetworkListManagerEvents *)this;024 }025 else026 {027 Result = E_NOINTERFACE;028 }029 030 return Result;031 }032 033 ULONG STDMETHODCALLTYPE AddRef()034 {035 return (ULONG)InterlockedIncrement(&m_ref);036 }037 038 ULONG STDMETHODCALLTYPE Release()039 {040 LONG Result = InterlockedDecrement(&m_ref);041 if (Result == 0)042 delete this;043 return (ULONG)Result;044 }045 046 virtual HRESULT STDMETHODCALLTYPE ConnectivityChanged(047 /* [in] */ NLM_CONNECTIVITY newConnectivity)048 {049 return S_OK;050 }051 052 private:053 054 LONG m_ref;055 };056 057 int _tmain(int argc, TCHAR** argv, TCHAR** Env)058 {059 CoInitialize(NULL); 060 061 //062 // 通过NLA接口获取网络状态063 //064 IUnknown *pUnknown = NULL;065 066 HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void **)&pUnknown);067 if (SUCCEEDED(Result))068 {069 INetworkListManager *pNetworkListManager = NULL;070 Result = pUnknown->QueryInterface(IID_INetworkListManager, (void **)&pNetworkListManager);071 if (SUCCEEDED(Result))072 {073 VARIANT_BOOL IsConnect = VARIANT_FALSE;074 Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);075 if (SUCCEEDED(Result))076 {077 printf("IsConnect Result %s\n", IsConnect == VARIANT_TRUE ? "TRUE" : "FALSE");078 }079 080 IConnectionPointContainer *pCPContainer = NULL;081 Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPContainer);082 if (SUCCEEDED(Result))083 {084 IConnectionPoint *pConnectPoint = NULL;085 Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);086 if(SUCCEEDED(Result))087 {088 DWORD Cookie = NULL;089 CNetworkListManagerEvent *NetEvent = new CNetworkListManagerEvent;090 Result = pConnectPoint->Advise((IUnknown *)NetEvent, &Cookie);091 if (SUCCEEDED(Result))092 {093 printf("Loop Message\n");094 MSG msg;095 while(GetMessage(&msg, NULL, 0, 0))096 {097 TranslateMessage(&msg);098 DispatchMessage(&msg);099 100 if (msg.message == WM_QUIT)101 {102 break;103 }104 }105 106 pConnectPoint->Unadvise(Cookie);107 108 pConnectPoint->Release();109 }110 }111 112 pCPContainer->Release();113 }114 115 pNetworkListManager->Release();116 }117 118 pUnknown->Release();119 }120 121 CoUninitialize();122 return 1;123 }因为NLA API是WINDOWS VISTA之后才有的,对于WINDOWS XP是不兼容的,但是WINDOWS XP下有一个方法可以达到同样的效果,可以参考文章Network Awareness in Windows XP,这个文章里的代码是C#的,其中关键的代码转换成C++01 void WaitForNetworkChnages()02 {03 WSAQUERYSET querySet = {0};04 querySet.dwSize = sizeof(WSAQUERYSET);05 querySet.dwNameSpac...
hex文件转换成C语言
文件有两种,一种是文本文件,一种是程序二进制文件,不管哪种文件都可以用十六进制编码来显示,称为hex文件。
1、文本Hex文件一般不需要转成C语言,更多的是程序二进制文件,用十六进制显示,可以转换成C语言,一般使用相应的反汇编程序来实现,这方面的工具很多,不同的平台略有不同。
Windows平台一般常用的OllyDbg、Windbg、IDA,Linux平台使用最多的是GDB和Linux版的IDA。
OllyDbg,简称OD,一般是软件逆向工程爱好者,最先使用的一个工具,但是因为当下不在更新,所以一般用一般用于学习使用,下图中左上角的区域即为反汇编区域 ,用户可以根据汇编指令,分析程序算法,然后自己编写代码。
在Windows平台,特别是x64平台,最好用的反汇编工具除还得是Windbg。
将程序载入Windbg后,可以输入u命令来查看程序的反汇编代码。
2、对于编程人员来说,逆向分析是一个基本的技能,但是往往不容易入门,这里举一个例子。
以一段早些年ShellCode的十六进制代码为例,代码如下图所示,这段不起眼的代码,实际上实现了一个下载者的功能。
拿到这样的十六进制代码,一般来说,先将其生成二进制文件,然后再分析其指令,通过反汇编指令再写出源码。
只需要将上面的十六进制代码,保存到C语言的字符串数组中,写入到一个Exe的文件空段中,再修改指令将其跳转到程序入口处即可,这个过程类似于软件安全领域的壳。
将十六进制代码写入一个exe文件后,就可以将exe文件载入动态调试器进行动态分析或者使用静态反汇编程序进行静态分析,两者的不同在于动态调试器是要运行程序的,而静态反汇编分析不需要运行程序,所以一般恶意程序,都采用静态分析。
反汇编开头的一段十六进制代码注释如下:4AD75021 5A pop edx ; 函数返回的地址保存到edx中4AD75022 64:A1 30000000 mov eax, dword ptr fs:[30] ; 取peb4AD75028 8B40 0C mov eax, dword ptr [eax+C] ; peb_link4AD7502B 8B70 1C mov esi, dword ptr [eax+1C] ; 初始化列表到esi4AD7502E AD lods dword ptr [esi] ; [esi]->eax + 8的位置即kernel32.dll的地址4AD7502F 8B40 08 mov eax, dword ptr [eax+8] ; eax=kernel32.dll的地址4AD75032 8BD8 mov ebx, eax ; ebx=kernel32.dll的基址4AD75034 8B73 3C mov esi, dword ptr [ebx+3C] ; esi = pe头偏移4AD75037 8B741E 78 mov esi, dword ptr [esi+ebx+78] ; esi为kernel32.dll导出表的偏移4AD7503B 03F3 add esi, ebx ; esi = kernel32.dll导出表的虚拟地址4AD7503D 8B7E 20 mov edi, dword ptr [esi+20] ; edi=ent的偏移地址4AD75040 03FB add edi, ebx ; edi = ent的虚拟地址4AD75042 8B4E 14 mov ecx, dword ptr [esi+14] ; ecx = kernel32.dll导出地址的个数4AD75045 33ED xor ebp, ebp ; ebp=04AD75047 56 push esi ; 保存导出表虚拟地址4AD75048 57 push edi ; 保存ent虚拟地址4AD75049 51 push ecx ; 保存计数4AD7504A 8B3F mov edi, dword ptr [edi]4AD7504C 03FB add edi, ebx ; 定位ent中的函数名4AD7504E 8BF2 mov esi, edx ; esi为 要查询的函数GetProcAddress即该call的下一个地址是数据4AD75050 6A 0E push 0E ; 0xe0是GetProcAddress函数的字符个数4AD75052 59 pop ecx ; 设置循环次数为 0xe4AD75053 F3:A6 repe cmps byte ptr es:[edi], byte ptr [esi] ; ecx!=0&&zf=1 ecx=ecx-1 cmps判断 GetProcAddress4AD75055 74 08 je short 4AD7505F ; 如果ENT中的函数名为GetProcAddress跳走4AD75057 59 pop ecx ; 不相等则将导出地址数出栈4AD75058 5F pop edi ; ent虚拟地址出栈4AD75059 83C7 04 add edi, 4 ; edi地址递增4字节 因为ENT的元素大小为4字节4AD7505C 45 inc ebp ; ebp用于保存ent中定位到GetProcAddress函数时的计数4AD7505D ^ E2 E9 loopd short 4AD75048 ; 循环查询4AD7505F 59 pop ecx4AD75060 5F pop edi4AD75061 5E pop esi4AD75062 8BCD mov ecx, ebp ; 计数保存于ecx4AD75064 8B46 24 mov eax, dword ptr [esi+24] ; esi+0x24 Ordinal序号表偏移地址4AD75067 03C3 add eax, ebx ; ordinal序号表的虚拟地址4AD75069 D1E1 shl ecx, 1 ; ecx逻辑增加2倍 因为ordinal序号是WOR类型下面是通过add 来求ordinal所以这里必须扩大2倍4AD7506B 03C1 add eax, ecx4AD7506D 33C9 xor ecx, ecx ; ecx=04AD7506F 66:8B08 mov cx, word ptr [eax] ; 保存取出的ordinal序号4AD75072 8B46 1C mov eax, dword ptr [esi+1C] ; eax 为kenrnel32.dll的EAT的偏移地址4AD75075 > 03C3 add eax, ebx ; eax = kernel32.dll的eat虚拟地址4AD75077 C1E1 02 shl ecx, 2 ; 同上,扩大4倍因为eat中元素为DWORD值4AD7507A 03C1 add eax, ecx4AD7507C 8B00 mov eax, dword ptr [eax] ; eax即为GetProcAddress函数的地址 相对虚拟地址,EAT中保存的RVA4AD7507E 03C3 add eax, ebx ; 与基址相加求得GetProcAddress函数的虚拟地址4AD75080 8BFA mov edi, edx ; GetProcAddress字符到edi4AD75082 8BF7 mov esi, edi ; esi保存GetProcAddress地址4AD75084 83C6 0E add esi, 0E ; esi指向...