我试图为一个简单的程序创建一个作弊,它基本上是一个.dll文件,当它使用它的基地址注入它时,它将改变主程序的整数值.问题是,我找不到使用作弊引擎主要是因为有多个级别指针与NEGATIVE?偏移.例如:
//Starting pointer address 0x0033FCF0 -> 200 //Finding second level pointer using "Find out what's accessing this address" in Cheat Engine **(mov eax,[ebp+08])** // **EAX=0x00000007**,**EPB=0x0033FCE8 => mov 00000007,[0033FCE8+08]** 2nd Level Pointer: **(0033FCE8+18) -> 200**
所以我继续使用“找出什么是……”来找到下一个指针,但是当使用T-SEARCH和第二级指针地址时,我会得到7到8个新的静态地址.
问题是,我不知道哪一个是正确的,因为作弊引擎REFUSES让我使用NEGATIVE添加指针?偏移.
例:
Base Pointer: **mov eax,[epb-18] !!!** // Notice the **MINUS**
并且除了一切之外,Cheat Engine拒绝接受具有负偏移的指针!
那么,是否有另一种从多个级别指针中查找基址的方法?
欢迎OlyDBG / Idapro解决方案.非常感谢你们!
这是我试图破解的简单程序的源代码:
#include <iostream> #include <conio.h> #include <windows.h> #include <stdlib.h> int main(){ int hp = 100; while(1){ std::cout << hp << std::endl; Sleep(3000); hp += 10; system("cls"); } return 0; }
我想要做的是用这个.dll编辑hp整数
#include <windows.h> #define BASE 0xBASE_POINTERS_ADDRESS_WHICH_I_NEED_TO_FIND #define OFFSET 0xTHE_OFFSET #define VALUE 90 void MainFunction() { while(1) { if (GetAsyncKeyState(VK_MENU)&0x8000 && GetAsyncKeyState('C')&0x8000) MessageBox(0,L"Alt + C was pressed!",L"MessageBox! ",0); *(int*)((*(int*)BASE) + OFFSET) = VALUE; Sleep(100); //Let the program rest,otherwise it hogs cpu resources. } } BOOL WINAPI DllMain(HINSTANCE MyInstance,DWORD reason_for_call,LPVOID PointerToVoid) { if (reason_for_call == DLL_PROCESS_ATTACH) CreateThread(0,(LPTHREAD_START_ROUTINE)&MainFunction,0); return true; }
顺便说一句,我试图破解惠普! 〜哦,等等,我已经说过了,哦,好吧,等等;)
谢谢你们,上帝保佑你们!
解决方法
CE允许您修改以持久方式存储在内存中的值.例如,在堆上,或在程序的静态数据中.
例如,C对象以确定的方式分配,因此它们永远不会移动.这就是为什么它们可以被一个在整个对象的生命周期内保持不变的指针引用.该对象有时由另一个拥有.如果找到指向所有者对象的指针,则会找到所谓的基指针.
例如 :
class Object { bool dummy; int someField; Object* child; };
现在假设你有一个3对象的嵌套树.这意味着您有一个根对象(n°1),其子对象是另一个对象(n°2),其子对象是另一个对象(n°3).想象一下,你做了这样的事情:
int main(int argc,char** argv) { Object root; // n°1 root.child = new Object(); // n°2 root.child->child = new Object(); // n°3 return 0; }
你有兴趣搞乱n°3的someField值.您知道someField相对于Object的地址是sizeof(bool)= 1.
所以(void *)&(object n°3)1是指向你想要的someField的指针.
现在,你如何找到指向对象n°3的指针?
知道child的相对地址是sizeof(bool)sizeof(int)= 5.我们知道指向对象n°3的指针是(void *)&(object n°2)5.
对象n°2的地址也是如此,我将把它留作练习.
但对象n°1怎么样?它没有在堆上分配.它在堆栈上.废话.所以我们必须找到另一种方法来找到存储对象n°1的地址.
局部变量存储在堆栈中.在汇编中,它们通过它们相对于寄存器EBP(或ESP,如果函数不改变堆栈)的偏移来标识.
EBP是堆栈的顶部,而ESP是堆栈的底部.
在这个例子中:
function foo() { int a; double b; }
当调用foo时,堆栈将增加到足以容纳a和b,即sizeof(int)sizeof(double)或12个字节. a将存储在EBP – sizeof(int)= EBP – 4(与ESP 8相同),b将存储在EBP – sizeof(int) – sizeof(double)= EBP – 12(与ESP相同).注意!编译器可以更改此顺序,因此变量的声明顺序在内存中不一定相同.优化也可以完全改变这一点.但是,让我们保持这个简单的好吗?
回到我们的主要例子.我们有哪些局部变量?只有根.因此root将直接位于EBP-9.但是,这只是当main是调用堆栈顶部的函数时.没有调试器,你就无法做到.
假设在调用main时我们的EBP是0028FF28(取自新编译的C程序).
然后根在(0x0028FF28 – 9)= 0x0028FF1F;
指向root.child的指针位于(0x0028FF1F 5)=(0x0028FF24);
因此,root.child位于* 0x0028FF24.
指向root.child-> child的指针位于(* 0x0028FF24 5)=(比方说10000)
然后root.child-> child在* 10000.
最后,root.child-> child.someField位于* 10000 3.
总结一下:你只需找到root的静态地址就可以找到其余的.
root不在堆上或任何类型的持久内存中,但是它位于main的堆栈上,它几乎在所有程序中持续存在,因此它几乎就像是永久性的.
CE通过扫描整个进程内存空间来帮助您找到静态地址
考虑到所有这些,您应该能够计算堆栈上的hp相对地址并找到一个静态指针(每次启动程序时,main都非常非常非常可能有静态帧地址).如果您需要帮助,请使用调试器!我推荐Immunity Debugger.