Recently finished a memory-based auto-trigger for the MMO Firefall. I blanked out some of the values because I'm hoping maybe Red5 (the company) will compensate me for the code since it's making me ungodly powerful in PvP as an Electron. I also removed a bunch of functions that aren't used (rightclick(), sendkey() etc..)
Awesome learning experience!
Firefall sets a value in memory based on what you are aiming at. It changes to one value for a player, another for a NPC/world object (printers, garages, etc), and is null when aiming at nothing (the ground/sky). First I search through a chunk of memory once while aiming at an object, finding all addresses with that value. (lines 130-154).
Since there are multiple hits (usually around 20), a second loop was needed to narrow down to the right address. After aiming at a player, it'll scan again running those previous addresses against the new expected values (lines 161-173). The left over value is (99% of the time) the right address.
For some reason, the first 5-10 leftclick() events sent to Firefall make me aim in crazy places, so after initiating the auto-trigger, I make it shoot a few times to settle itself down (lines 183-187).
Since I'm loaning this EXE to a friend in-game to play with me, I added the function kaboom(), which when I say a phrase in-game, closes his Firefall process. This way if we get into a match against each-other, he can't use my own tool against me :)
1: #include <iostream>
2: #include <Windows.h>
3: #include <TlHelp32.h>
4: #include <tchar.h>
5:
6: using namespace std;
7:
8: void leftclick()
9: {
10: PINPUT click = new INPUT;
11: click->type = INPUT_MOUSE;
12: click->mi.dwFlags = 0x2;
13: click->mi.mouseData = 0;
14: click->mi.time = 0;
15: click->mi.dwExtraInfo = 0;
16: SendInput(1,click,sizeof(INPUT));
17: click->mi.dwFlags = 0x4;
18: SendInput(1,click,sizeof(INPUT));
19: }
20:
******************
******************
115: #define PC_BEGIN 0x**
116: #define PC_END 0x**
117: #define NPC_BEGIN 0x**
118: #define NPC_END 0x**
119:
120: DWORD findAddy(HANDLE hHandle)
121: {
122: DWORD resultsCounter=0, bigCounter=0, goodHitsA[1000], goodHitsB[1000],betterHit=0,endCounter=0;
123: char y[1000], z[1000];
124: DWORD addy=0x00000000;
125: DWORD x[1000];
126:
127: cout << "Aim at NPC/world object, hit enter, and wait.";
128: cin.get();
129:
130: while(bigCounter<0x01000000)
131: {
132: ReadProcessMemory(hHandle, (LPVOID)addy, &y[0], sizeof(&y[0]), 0);
133: if(y[0]==NPC_BEGIN)
134: {
135: //printf("0xPC_BEGIN at %08X\n", addy);
136: for(int i=0;i<8;i++)
137: {
138: addy++;
139: ReadProcessMemory(hHandle, (LPVOID)addy, &y[i+1], sizeof(&y[i]), 0);
140: x[i]=addy-1;
141: }
142: //ignoreme
143: if(y[0]==NPC_BEGIN&&y[7]==NPC_END)
144: {
145: printf("***HIT***\tx[0] = %08X\n", x[0]);
146: goodHitsA[resultsCounter]=x[0];
147: goodHitsB[resultsCounter]=x[7];
148: resultsCounter++;
149: }
150: bigCounter++;
151: }
152: addy++;
153: bigCounter++;
154: }
155:
156:
157: cout << "Now aim at a player, and hit enter." << endl;
158: cin.get();
159:
160:
161: for(int i = 0; i < resultsCounter;i++)
162: {
163: ReadProcessMemory(hHandle, (LPVOID)goodHitsA[i], &z[i], sizeof(&goodHitsA[i]), 0);
164: ReadProcessMemory(hHandle, (LPVOID)goodHitsB[i], &y[i], sizeof(&goodHitsB[i]), 0);
165: //printf("z[0] = %08X\ty[0] = %08X\n", z[0], y[0]);
166: if(z[i]==PC_BEGIN&&y[i]==PC_END)
167: {
168: betterHit=goodHitsB[i];
169: cout << "Press Enter to initiate auto-trigger. GET SOME GET SOME!!!\n";
170: cin.get();
171: Sleep(2000);
172: }
173: }
174: if(!betterHit)
175: {
176: printf("Unsuccessful, best bet is to restart FireFall completely and try again.");
177: return 1;
178: }
179:
180: //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
181: // Clicks to stop the spazzing
182: //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
183: for (int i=0;i<10;i++)
184: {
185: leftclick();
186: Sleep(200);
187: }
188:
189: return betterHit;
190: }
191:
192: void kaboom(HANDLE hHandle)
193: {
194: int counter=0;
195: DWORD base=0x00000000;
196: char y[20];
197: while(counter<0x01000000)
198: {
199: ReadProcessMemory(hHandle, (LPVOID)base, &y[0], sizeof(&y[0]), 0);
200: if(y[0]==0x**)
201: {
202: //printf("0x** at %08X\n", base);
203: for(int i=0;i<16;i++)
204: {
205: base++;
206: ReadProcessMemory(hHandle, (LPVOID)base, &y[i+1], sizeof(&y[i]), 0);
207: }
208: if(y[0]==0x**&&y[1]==0x**&&y[2]==0x**&&y[3]==0x**&&y[4]==0x**&&y[5]==0x**&&y[6]==0x**&&y[7]==0x20&&y[8]==0x6B&&y[9]==0x61&&y[10]==0x62&&y[11]==0x6F&&y[12]==0x6F&&y[13]==0x6D&&y[14]==0x21)
209: {
210: TerminateProcess(hHandle, 0);
211: }
212: counter++;
213: }
214: base++;
215: counter++;
216: }
217: }
218:
219: int main()
220: {
221:
222: //************************************************
223: // Gets PID of FirefallClient.exe
224: //************************************************
225: HANDLE hHandle;
226: HANDLE hSnapshot;
227: PROCESSENTRY32 entry;
228: entry.dwSize=sizeof(entry);
229: hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
230: if(Process32First(hSnapshot, &entry) == TRUE)
231: {
232: while(Process32Next(hSnapshot, &entry)==TRUE)
233: {
234: if (_tcscmp(entry.szExeFile, TEXT("FirefallClient.exe"))==0)
235: {
236: hHandle = OpenProcess(PROCESS_VM_READ, FALSE, entry.th32ProcessID);
237: break;
238: }
239: }
240: }
241: if(!hHandle)
242: {
243: printf("OpenProcess() Failed!\n");
244: return 1;
245: }
246: else
247: {
248: printf("FirefallClient.exe (PID: %d) opened successfully\n", entry.th32ProcessID);
249: }
250:
251: DWORD addy;
252: addy=findAddy(hHandle);
253: char buffer;
254: while(1)
255: {
256: //for(int i=0;i<300000;i++)
257: //{
258: ReadProcessMemory(hHandle, (LPVOID)addy, &buffer, sizeof(&addy), 0);
259: if(buffer!=0)
260: {
261: leftclick();
262: Sleep(50);
263: }
264: Sleep(10);
265: //}
266: //kaboom(hHandle);
267: }
268: }
At first, I had the PID hard-coded in to
the program and had to re-compile each time. Then I evolved to using a
command line argument. Finally, I stepped it up to automatically
finding it out based on the executable name, which makes things super
easy! Unfortunately I had some issues comparing the text from a
PROCESSENTRY32 structure with quoted text (line 234), so this took
longer than it should have. Apparently PROCESSENTRY32.szExeName is
stored as a TCHAR (unicode) and quoting text makes it (const char *) so
it kept bitching at me. There's also a way to do it with a window name,
but since
Firefall is in debug-mode, the window title was constantly changing to
show KBp/s, framerate, etc.
The next step would be somehow attaching a debugger to Firefall (it's anti-cheat has an anti-debugger in it) and finding out the exact offset so I could just have the right address every time and don't have to scan for it. Since the location in memory changes every time I run Firefall, the scanning is necessary, but being able to just run/stop it on demand would be fantastic.
Whatever. Win!