I just played solo with cheatengine open and attached for 15 minutes using the file I posted here.
not sure what is causing your issue, and I don't doubt you, but I have a different outcome here as I am not experiencing any issues.
I just played solo with cheatengine open and attached for 15 minutes using the file I posted here.
Sorry that I did not respond to this sooner, as am not in here that much. If you haven't figured this out or need some help, PM me and I can send you some info to help, although the method they are using and how to write to it and when are tricky, at least it was for me.Launchpad wrote: ↑Sat Aug 03, 2019 7:08 amHey BruteForce,
I ended up looking at this some today too. I did notice you could kill the anti-cheat EXE and it would just relaunch, but I also noticed it wasn't signed, checked or whatnot and could be replaced. I didn't go any further with it however like you did. According to documentation, replacing the EXE with a fake one should trigger another UE-based anti-cheat trigger, but that keeps to be circumvented by your "app crash" method. This isn't some super professional anti-cheat, but I'd be curious studying that later just "for fun".
I'm able to use cheat programs fine with the actual EXE in place. In my experience, it only checks for Window Titles and also Win32 window class names as far as I can tell so far. I didn't read all the source yet however. In fact, it's very loosely coded where it'll close on false positives if you have some other Pascal/Lazarus compiled programs open, for example.
I started to investigate value editing. I noticed complex structures like your inventory is not "encrypted". I'm still easily able to change vector levels and enchantments on my gear. However credits and materials seem to use this encryption method. I haven't spent long on it yet, but haven't figured it out. Mind sharing? Appears things like numbers get treated like strings, swapped out with the same position in the key (or is there shifting?), and converted back to an INT from a string. Not sure if they are using the default KEY or a custom one I need to dig up. Anyways, if you're willing to share to save me the time I'd appreciate it. Let me know if I can be of any help to you.
You will have to actually buy it and get the latest iteration of it, since they added all this stuff (encryption, anti cheat tools, etc.) in the last past. Best I can tell their last patch, honestly, was mostly anti-cheat patch.
Launchpad wrote: ↑Sat Aug 03, 2019 7:08 amHey BruteForce,
Mind sharing? Appears things like numbers get treated like strings, swapped out with the same position in the key (or is there shifting?), and converted back to an INT from a string. Not sure if they are using the default KEY or a custom one I need to dig up. Anyways, if you're willing to share to save me the time I'd appreciate it. Let me know if I can be of any help to you.
I noticed the code area in the .exe in x64dbg, but the .exe does not detect anything so I assume this code is dormant or is called by fails. I've done nothing with this function/section in the game.
This method doesnt work for me... Game detect n close my "Minesweeper CE"SunBeam wrote: ↑Sat Aug 03, 2019 11:35 amHere's how to do it for Cheat Engine (been using this for a while, for games like StarCraft - the revamped one):
- Settings > Debugger Options > User kernelmode debugger
- Settings > Debugger Options > Use Global Debug routines
- Settings > Extras > all 3 up top (Query, Read/Write, Open)
- while in Settings, click on 'About CE', then in the window that opens RIGHT-CLICK "Your system supports DBVM"
- slowly offload each CPU into DBVM (click on CPU0, wait a bit; repeat with the rest)
- run the LUA script below (in Memory View > Ctrl+L)
Code: Select all
dbk_initialize() dbk_useKernelmodeOpenProcess() dbk_useKernelmodeProcessMemoryAccess() dbk_writesIgnoreWriteProtection(true) openProcess('cheatengine-x86_64.exe') autoAssemble([[ kernelbase.SetProcessMitigationPolicy: xor rax,rax ret ]])
- open Process List
- run the script below to change window names
Here's me having scanned and debugging StarCraft with Cheat Engine. A game that has a ton shit of more professional detection mechanismsCode: Select all
for i=0, getFormCount()-1 do getForm(i).Caption="Minesweeper" end getApplication().Title="WEEEE" r=registerFormAddNotification(function(f) local t=createTimer() t.Interval=1 t.Enabled=true t.OnTimer=function(tmr) f.Caption="Whoopdeedoo" tmr.destroy() end end)
But yeah, bottom line is understanding what is it they detect. For example, Denuvo in MK11 also detects the "Add Address manually" button/window
BR,
Sun
The find window checks work on my PC though, I had to hook the FindWindow function. It gets called 4 times every 3 seconds.BruteForce wrote: ↑Thu Aug 08, 2019 2:56 am
I noticed the code area in the .exe in x64dbg, but the .exe does not detect anything so I assume this code is dormant or is called by fails. I've done nothing with this function/section in the game.
auto HND = FindWindowA((LPCSTR)"WinDbgFrameClass",NULL); if (HND) {return true;}
HND = FindWindowA((LPCSTR)"WinDbgFrameClass",NULL); if (HND) {return true;}
HND = FindWindowA((LPCSTR)"OLLYDBG",NULL); if (HND) {return true;}
HND = FindWindowA((LPCSTR)"Window",NULL); if (HND) {return true;}
Standard x64dbg seems to be able to bypass:
FARPROC IDebuggerPresent = GetProcAddress(Kernel,"IsDebuggerPresent");
as well.
Yeah, this is stupid. This is the sort of thing many of us worry about with EAC and other anticheats that take over your kernel and do callbacks and detours from ring 0. That they are not just taking over kernel calls from an app, but SYSTEM WIDE, and that they can be abused or can detect something inaccurately and well, do whatever, or ban you, or improperly 'reset' after they are done, or a million other things.Launchpad wrote: ↑Thu Aug 08, 2019 4:32 amI think it's funny they do a window class check on any window with class name "Window", which will be ANY Pascal application complied in Lazarus (let alone maybe just some random Win32 app), not just Cheat Engine. False positive chance pretty high there. Thanks for sharing, I was just toying around with this game because I find it enjoyable and an easy target to reacquaint myself with reversing.
I'll do some more research on this and future games and try to add helpful information as well.
BruteForce wrote: ↑Thu Aug 08, 2019 2:49 amLaunchpad wrote: ↑Sat Aug 03, 2019 7:08 amHey BruteForce,
Mind sharing? Appears things like numbers get treated like strings, swapped out with the same position in the key (or is there shifting?), and converted back to an INT from a string. Not sure if they are using the default KEY or a custom one I need to dig up. Anyways, if you're willing to share to save me the time I'd appreciate it. Let me know if I can be of any help to you.
0.6.4.2
INVENTORY ITEMS
=================
Game-Win64-Shipping.exe+70D051 - 80 7D BC 00 - cmp byte ptr [rbp-44],00 { 0 }
Game-Win64-Shipping.exe+70D055 - 89 45 B7 - mov [rbp-49],eax
[RSP+CC] == OFFSET (0-0x1C), iteration, or identifier number (0 - 'x')
[RSI+20] or [RSI+30]== number of digits + 1
[RSI+18] or [RSI+28]== pointer to encrypted data, holding info 0x3D is number 9, so:
this (below) is 999,999 (or 999999)
3D 00 3D 00 3D 00 3D 00 3D 00 3D 00
and use 7 as number of digits (999999 is 6 digits, + 1)
OFFSET at [RSP+CC] and what it holds
--------------------------------------
0 Credits
1 DNA
2 Ecos of the Plague
3 Unseen Trinket
4 Jade
5 and higher rest of inventory
Game-Win64-Shipping.exe+70D009 - 0F84 2B010000 - je Game-Win64-Shipping.exe+70D13A
Game-Win64-Shipping.exe+70D00F - 33 C0 - xor eax,eax
Game-Win64-Shipping.exe+70D011 - 48 8D 54 24 40 - lea rdx,[rsp+40]
Game-Win64-Shipping.exe+70D016 - 48 8B CB - mov rcx,rbx
Game-Win64-Shipping.exe+70D019 - 48 89 44 24 40 - mov [rsp+40],rax
Game-Win64-Shipping.exe+70D01E - 48 89 44 24 48 - mov [rsp+48],rax
Game-Win64-Shipping.exe+70D023 - 48 89 45 87 - mov [rbp-79],rax
Game-Win64-Shipping.exe+70D027 - 48 89 45 8F - mov [rbp-71],rax
Game-Win64-Shipping.exe+70D02B - 48 89 45 97 - mov [rbp-69],rax
Game-Win64-Shipping.exe+70D02F - 48 89 45 9F - mov [rbp-61],rax
Game-Win64-Shipping.exe+70D033 - 48 89 45 BF - mov [rbp-41],rax
Game-Win64-Shipping.exe+70D037 - 48 89 45 C7 - mov [rbp-39],rax
Game-Win64-Shipping.exe+70D03B - 48 89 45 CF - mov [rbp-31],rax
Game-Win64-Shipping.exe+70D03F - 48 89 45 D7 - mov [rbp-29],rax
Game-Win64-Shipping.exe+70D043 - E8 48E9FFFF - call Game-Win64-Shipping.exe+70B990
Game-Win64-Shipping.exe+70D048 - 48 8D 4E 08 - lea rcx,[rsi+08]
Game-Win64-Shipping.exe+70D04C - E8 4FB9CEFF - call Game-Win64-Shipping.exe+3F89A0
Game-Win64-Shipping.exe+70D051 - 80 7D BC 00 - cmp byte ptr [rbp-44],00 { 0 }
Game-Win64-Shipping.exe+70D055 - 89 45 B7 - mov [rbp-49],eax
Game-Win64-Shipping.exe+70D058 - 74 07 - je Game-Win64-Shipping.exe+70D061
Game-Win64-Shipping.exe+70D05A - 3B 45 DF - cmp eax,[rbp-21]
Game-Win64-Shipping.exe+70D05D - 0F9D 45 BC - setge byte ptr [rbp-44]
Game-Win64-Shipping.exe+70D061 - 48 63 5F 08 - movsxd rbx,dword ptr [rdi+08]
Game-Win64-Shipping.exe+70D065 - 8D 43 01 - lea eax,[rbx+01]
Game-Win64-Shipping.exe+70D068 - 89 47 08 - mov [rdi+08],eax
Game-Win64-Shipping.exe+70D06B - 3B 47 0C - cmp eax,[rdi+0C]
Game-Win64-Shipping.exe+70D06E - 7E 0A - jle Game-Win64-Shipping.exe+70D07A
Game-Win64-Shipping.exe+70D070 - 8B D3 - mov edx,ebx
Game-Win64-Shipping.exe+70D072 - 48 8B CF - mov rcx,rdi
Game-Win64-Shipping.exe+70D075 - E8 F6CBBCFF - call Game-Win64-Shipping.exe+2D9C70
Game-Win64-Shipping.exe+70D07A - 48 6B DB 70 - imul rbx,rbx,70
Game-Win64-Shipping.exe+70D07E - 48 8D 54 24 40 - lea rdx,[rsp+40]
Game-Win64-Shipping.exe+70D083 - 48 03 1F - add rbx,[rdi]
Game-Win64-Shipping.exe+70D086 - 48 8B CB - mov rcx,rbx
Game-Win64-Shipping.exe+70D089 - E8 325EB4FF - call Game-Win64-Shipping.exe+252EC0
Game-Win64-Shipping.exe+70D08E - 48 8D 4B 10 - lea rcx,[rbx+10]
Maybe there is a better spot to do this, but this seems to be the spot where you can divide out items.
As we discussed, yes the values are stored as unicode script text and the script text then gets converted (each 2 byte 'letter') to an offset to a table of the actual numbers (i.e. text of 0-9).
Each address holding the encrypted or 'stored' value is written over, read from, converted, then extracted the value, then immediately in reverse converted back in a loop.
No, sorry. Lost interest; actually, never gotten to do anything about it. However the topic is full with information. Should help you out.TheStranger81 wrote: ↑Sun Feb 23, 2020 10:53 pmSunbeam any chance you got around to check this out? Killing us, only CH has a trainer
Users browsing this forum: No registered users