SunBeam Posted April 2, 2015 Author Posted April 2, 2015 (edited) In Assassin's Creed: Unity, I want to hook this piece of code: I want to place a JMP there to a code-cave of mine where I acquire value of RCX register as the pointer used for an internal DebugMenu. What I did now was to debug every byte at that location: 140EA52A0: +0: 48 89 5C 24 08 | +5: 48 <- I am interested mainly in the byte at 140EA52A5. That's the one I will be restoring the CRC for. Using Cheat Engine as the debugger, I found that RAX register (holding the CRC value) is E1A44BE4 when 140EA52A5 is checked. One down, one more to go. Am following JohnWho's methodology here Now, back to VMProtect, code is checked within this function: 1455D741F - 32 02 - xor al,[rdx] <-- classic XOR operation 1455D7421 - F9 - stc 1455D7422 - E9 9C060000 - jmp 1455D7AC3 .. 1455D7AC3 - F8 - clc 1455D7AC4 - F6 C4 85 - test ah,-7B 1455D7AC7 - 48 83 C2 01 - add rdx,01 <-- move to next address 1455D7ACB - E9 1E2F19FD - jmp 14276A9EE .. 14276A9EE - E9 43BCE602 - jmp 1455D6636 .. 1455D6636 - FF 4D 00 - dec [rbp+00] <-- decrement counter 1455D6639 - E9 0C5AFFFF - jmp 1455CC04A .. 1455CC04A - E9 207F0200 - jmp 1455F3F6F .. 1455F3F6F - 0F85 897EFDFF - jne 1455CBDFE --> jumps at [1] .. [ 1455CBDE2 - 48 8B 55 00 - mov rdx,[rbp+00] <-- RBP contains the checked address 1455CBDE6 - 66 0FAC C9 0D - shrd cx,cx,0D 1455CBDEB - 66 D3 - 1455CBDED - F1 - db F1 1455CBDEE - 48 83 C5 08 - add rbp,08 1455CBDF2 - 66 0FA5 F1 - shld cx,si,cl 1455CBDF6 - 0FAC D9 16 - shrd ecx,ebx,16 1455CBDFA - FE C1 - inc cl 1455CBDFC - 29 C0 - sub eax,eax ] 1455CBDFE - 66 0FBD CB - bsr cx,bx <-- [1] So what I have to do more is hook 1455D7ACB: 1455D7ACB: +0: E9 20 7F 02 00 | +5: 51 (1455CC04F added to list, CRC is ) EDIT: I can now say they're using threads. If I break on the XOR and try to trace code with regular stepping it so happens that debugger lands in another thread. I'm basically executing same code in two threads, starting with the location I put the breakpoint on, asynchronous. Problem I'm having now is this one: The VMProtect code is checked from multiple locations (I remember SecuROM) So I have to chain-patch these spots to get a working bypass. So far I found 3 checks for CRC: main game code is checked in one spot (let's call it XOR_1); XOR_1 is checked by itself and XOR_2 (in another place); XOR_2 is checked by XOR_1, itself, and XOR_3 (in another place); XOR_3 is checked by XOR_2 and itself I don't know if there are any other timed checks (will leave game running for a while). So basically, my check doesn't mimic properly their implementation. EDIT: Aha! A 4th one poped up! BR, Sun Edited April 2, 2015 by SunBeam 2
simple Posted April 2, 2015 Posted April 2, 2015 Your rules are pretty confusing when u say stuff like this in your challenge... So, the elegant way to disable the check (I think they need a timer or something, thread, to infinitely check on the code via VMProtect's SDK API) is to disable the timer/thread/etc. - whatever they use (figuring out first what's the used method). But it doesn't matter whether it's virtualized x86, x64, arm, a process, a thread, a callback, or on a mcu that communicates to the host machine via a satellite on Jupiter's 3rd moon, there's always going to be a way to block the code and there's no such thing as a "good implementation" of stuff like this. If it can't be done from user space then definately from the kernel. Your method is time consuming very unstable. Mine is fast and stable, but to each their own - good luck ; ) 2
Conquest Posted April 2, 2015 Posted April 2, 2015 (edited) The function which is used for vmp's hash checking is written as something similar to ecx = eax = 0; for (i = 0; i < Size; i++) { ecx = eax ecx = ecx >> 0x19 eax = (eax << 0x07) | ecx eax = (eax & 0xFFFFFF00) | (eax & 0xFF) ^ memaddress[i] }I dont see the point of patching the handlers mainly because it will require one to modifying the nature of the handlers and make a backup of original file . If handler integrity check is enabled, it will be harder. The simplest method is to patch the VMP crc function call at all . Your vmp hash check handler starts at 40CC9DMem Address and range to checked can be seen as pushed values via EBP Edited April 2, 2015 by Conquest
SunBeam Posted April 2, 2015 Author Posted April 2, 2015 (edited) @simple: I haven't properly checked the target when I thought of the implementation in this test app. It looks like there's checks to the checks that check the checks Something like that. The idea here was to actually follow VMProtect flow and find the return of IsValidImageCRC API. Or as Conquest has put it, patching the CALL itself. Again, in this test application you know where it is. In others you don't. How you plan to find it, that's my goal. Simply put, the timer was my implementation of "calling a check function at a given interval". The timer was not the target here. What I said about it is related to my main target, ACU. Thought it would apply to it, but I see things are different. Back to the real target (not this test one of mine), how do you plan to find each and every piece of code that accesses the rest of them? The way I see it CRC is done at certain intervals, just to be sure at any given point in time one checker (any of the checkers) isn't patched. BR, Sun Edited April 2, 2015 by SunBeam
Conquest Posted April 2, 2015 Posted April 2, 2015 (edited) Again, in this test application you know where it is. In others you don't. How you plan to find it, that's my goal.I wont spoil the fun of yours, but lets say it happens this way Lets say function is something likenormalfunc{//do operationif(VMProtectIsValidImageCRC()){//You go gurl!};else {//naughty boy};}Equivalent asm is //original asmcall VMProtectIsValidImageCRC()test eax,eax//do whatever requestedWhen vmped it will be differentEach function will be compiled as different vm I wont reveal all the details but the vmp when switching function has to initiate a complete cleanup phase to keep the stack exact replica of original execution. it simply means the VMProtectIsValidImageCRC() is assumed as different function call unknown to vmp and full call jump is requested. It will be something similar to ; GetI32 (VMProtectIsValidImageCRC function address hardcoded and encrypted inside pcode-store); CleanUp (restores Stack and registry as emulated inside vm); Cleanup handler Ret to new function; VMProtectIsValidImageCRC() is evaluated // This phase can be replaced.; Vm Execution of original function restoresExact details is too large to explain here and i am not willing to share it atm since i dont have complete grasp of it yet. Basic is you have t find the return handler to know the call jumps. Its same for themida as well. Edited April 2, 2015 by Conquest
White Posted April 4, 2015 Posted April 4, 2015 (edited) Hi, my solution. 0040B53F 8B4424 18 mov eax,dword ptr ss:[esp+0x18]change to 0040B53F 33C0 xor eax,eax 0040B541 B0 01 mov al,0x1 Edited April 4, 2015 by White、、 1
SunBeam Posted April 5, 2015 Author Posted April 5, 2015 (edited) Good work, White @simple & Conquest: This is basically where I kinda stopped in terms of reversing - virtualization. I consider it takes an awful amount of time to get the hang of it, like learning a whole programming language (but more intricate), time I don't really have nowadays (work, fiancé, house in the plans etc.). I am trying to proceed as I can (and know, mostly) making use of what I've grasped so far - but damn willing to understand anything anyone throws at me. The initiative is there. With regards to my target(s), I noticed both Assassin's Creed: Unity and Far Cry 4 have the same mechanism implemented. One checks verifies the integrity of the other. My understanding of what happens from target launch till it being actually in memory here is the following: - VMProtect performs its usual checks; - unpacks the target in memory; - creates checksums of certain memory sections (or chunks of code); - once done, game will use those active checks to verify (at given intervals) if game/application code has been altered; - some of these checks check both themselves and other checks that check them (lol); Since patching the checks to return the correct checksums is a bit tedious: a. Either intercept VMProtect's checksum generation routine and make it checksum the already-altered memory (that way it won't bitch when you have the hook already there); b. Swap base pointer in the XOR loop: xor al,[rdx] <- rdx is base + offset; Plan would be to load-up the unpacked module (.exe or .dll - or at least some sections I know it checks) in memory and when the XOR is hit, redirect it to check the dummy memory instead of the actual memory (base + offset -> dummy_base + same offset). It would be always intact (the dummy). BR, Sun P.S.: Got no knowledge of kernel-mode stuff, so.. yeah.. Edited April 5, 2015 by SunBeam 1
Conquest Posted April 5, 2015 Posted April 5, 2015 You can check This link to have some rough idea about how to bypass the protection (ignore the mushroom game specific parts and check the vmp related part only). One thing i didnt mention is that ,there is not specific way to bypass these checks unless modifying the whole source, reason is there can be as great as 10 separate vm machines running making 10 separate hash check handlers executing(excluding handler integrity checks). Patching all of them is cumbersome.
portbinder Posted April 6, 2015 Posted April 6, 2015 cracking the check and algorithming the checksum is different. Sometime cracking the checks doesnt work
SunBeam Posted April 6, 2015 Author Posted April 6, 2015 (edited) Hi Conquest. MapleStory was one of the games I used to work on at some point. But at the time, it was all about unpacking (they used ASProtect back then, moved to Themida later on) and doing what I described above: finding out how the memory is checked and changing pointer to use the dummy loaded in memory. But yeah, it was just 1 check. Mostly simple stuff to an intermediate reverser. Very interesting article, summarizing my thoughts exactly In the meantime, I'll try and update my test target with some extra checks and an approach on how to swap pointer to checked memory. BR, Sun P.S.: MapleStory is still with Nexon? I remember they sold out the title Edited April 6, 2015 by SunBeam
SunBeam Posted April 6, 2015 Author Posted April 6, 2015 (edited) @Conquest: Now I understand why I've seen two types of checks: a. First set of checks in Unity or Far Cry 4 is VMProtect's - let's say - IsValidImageCRC; these are the XOR r8,[r32/r64] instructions;b. Second set of checks is comprised of instructions like MOV AX,[RDX]; Now, for a., we talked about the generics: start, size, RAX/EAX holds the hash value. Well, for b., the CRC value is someplace else. What I'm curious about is to debug the app and see if for this portion it checks I get same result with a regular CRC32 compute. BR,Sun Edited April 6, 2015 by SunBeam
Conquest Posted April 6, 2015 Posted April 6, 2015 P.S.: MapleStory is still with Nexon? I remember they sold out the title It belonged to wizet and nexon bought out wizet or something like that. Now its all about pay to win
Conquest Posted April 6, 2015 Posted April 6, 2015 (edited) @Conquest: Now I understand why I've seen two types of checks: a. First set of checks in Unity or Far Cry 4 is VMProtect's - let's say - IsValidImageCRC; these are the XOR r8,[r32/r64] instructions;b. Second set of checks is comprised of instructions like MOV AX,[RDX]; Now, for a., we talked about the generics: start, size, RAX/EAX holds the hash value. Well, for b., the CRC value is someplace else. What I'm curious about is to debug the app and see if for this portion it checks I get same result with a regular CRC32 compute. BR,SunI will add a few more information to aid you in debugging , there are separate handlers for operations , Read operations has 3 types of Heap read(byte,word and dword), stack read and hash check( total 7 atleast ), same with write operations. If the program has something likeMov R32,[R32]It will be Dword read handler mov eax,[ebp]add ebp,4mov eax,[eax]mov [ebp],eaxAnd so on for other data sizes . It is possible that you may encounter 30~40 handlers reading memory as different type of original instructions being changed into different type of handlers (ie. byte,word, dword or even tricking memory operations by doing them on stack) etc. So it is really irritating fixing all of them. Edited April 7, 2015 by Conquest
JohnWho Posted April 6, 2015 Posted April 6, 2015 I got lost in code but remember the memory crc check check itself so remember to fix value after the hook itself!
SunBeam Posted April 6, 2015 Author Posted April 6, 2015 (edited) I tested something today. I've dumped the target at OEP and fixed PE header (contained lots of crap). Then did the following: [ENABLE] alloc( hook, 256 ) alloc( dummy, 120000 ) label( originalcode ) loadbinary( dummy, C:\Documents and Settings\Administrator\Desktop\dumped.exe ) // our dumped dummy hook: push eax push ecx mov eax,[ebp] // get address from [ebp] mov ecx,target.exe // get ImageBase sub eax,ecx // get offset add eax,dummy // find location in dumped dummy mov [ebp],eax // swap checked address pop ecx pop eax originalcode: neg dl sar dl,cl mov edx,[ebp] jmp 40CCA4 // return back 40CC9D: jmp hook // hooked handler [DISABLE] 40CC9D: neg dl sar dl,cl mov edx,[ebp] dealloc( hook ) dealloc( dummy )This one actually works. Fun fact is active memory is not checked anymore. If there would be other checkers, re-routing would be done in the same way, I guess. BR,Sun Edited April 6, 2015 by SunBeam
JohnWho Posted April 6, 2015 Posted April 6, 2015 Last time i hacked games was when Battlefield 2 was in, and back then the easiest way to hook code and avoid punkbuster was to hook dma pointers... no work anymore? 1
Solution MistHill Posted May 25, 2015 Solution Posted May 25, 2015 Well, this topic is very interesting indeed.AFAIK, VMProtect usually includes four types of code integrity checks in an application protected with all advanced options enabled.1. File CheckAs SunBeam said, APIs called: CreateFile, CreateFileMapping, and MapViewOfFile.This happens during the shell code execution, i.e. between the target's entry point and the OEP.For this InlineMe, the followings are checked. Address Length Hash ------- ------ ----#00000001 003D0170 00010E78 D2953B20#00000002 003E1018 000061E8 632E395E#00000003 003D012C 0000003C 1EBECA14#00000004 003D0000 00000128 10C6C1DDFile Mapping Address: 003D0000Normally only 4 items in the table, and table itself not Hash checked. 2. Memory Check #1This is for verifying the file image in memory when the target loaded.If you examined the table records, you'll figure out that it's also a file check!Large part of the records are for .vmp1 section validation, only few for PE Header.Table size varies from different version or target.There is a hash check for table itself, and the valid Hash stored at some place, which can be easily patched. 3. Memory Check #2This is the memory check in a real sense, and applies mainly for the application.If the application was compressed, it happens after the user code, data and resource got unpacked.Table size is more bigger than the previous one, and the worse thing is that the table's Hash is hardcode in PCODE!In contrast with the Memory Check #1, records in the table not all meaningful. There is a End Flag, after that all the data is garbage. These three checks above are performed at the shell code execution stage.The record in table can be defined as:typedef struct { long EncryptOffsetRVA; long EncryptLength; long EncryptHash;} VMP_HashCheck_Record;The check procedure: a) decrypting OffsetRVA, +Modulebase, +Reloc. Factor; decrypting Length; c) call getHash handler to calculate Hash; d) encrypting the Hash; e) comparing it with the one in record.4. Random Memory CheckNo this kind of check in SunBeam's unsophisticated InlineMe.If the "Check the integrity of VM objects" option enabled, and a piece of the application code was virtualized, it will have an opportunity to show up.A check table does exist also, in which only the offset RVA are encrypted, and each length is one byte long for better execution performance.This silently check could be done many times in a virtualized code portion, but only one record is picked up randomly by the vRdtsc handler.According to VMProtect's help document, "A silent check means that the protected program will not show any messages in case the integrity of VM objects is broken, but it will cause the virtualized code to function incorrectly, which will lead to critical errors and, therefore, to the complete crash of the protected program." Okay, what the hell is going on within the SDK API VMProtectIsValidImageCRC?It's just the Memory Check #1 & #2!As Conquest mentioned previously, the getHash handler here is very very important!It's the critical clue for inline patching, even repacking a VMP target IMHO.If you logged the getHash handler(entry: 0041847A for vmp1) from the target's entry(00414699) to OEP(00401224), you'll find out that all the three checks are performed even this target not packed!Which means the VMProtectIsValidImageCRC function has been called once by the shell code in .vmp1 section.After read the log of the second getHash handler(entry: 0040CC9D for vmp0) between two Timer function CheckMemory(00401000) calls, it can be proved that only Memory Check #1 & #2 been done!Before continuing, let's discuss a little about foregoing approaches.White's solution is to patch the VMProtectIsValidImageCRC's result, it's simple and excellent only for this target!But, it's not the good approach because the patch point is within vRet handler, which is not generally applicable and dangerous in other case!First, the return value gets crap when went back to normal code from some virtualized user function or other SDK API in an application protected.Second, if the "Encrypt registers at VM output" option enabled, the return values at this point must be decrypted by another routines in different places.The ultimate aim is to prevent these checks or altering the content of tables.The more professional way is to patch the PCODE, that is difficult and needs advanced skill!The easy way is to hook the getHash handler, and patch the returns, somewhat as JohnWho did.The attached script is my method which just for demonstrating how to patch getHash handler and Memory Check #2 table, it's proper and enough for this scenario, I think.Followings are some references for this InlineMe.Modulebase: 00400000Imagebase: 00400000Memory Check #1 Table=====================Address: 00412180, Size: 00000210(0000002C Items), Table Hash: 84268688Item eOffset eLength eHash Decrypting dOffset dLength cHash ceHash----- ------- ------- ----- ------- ------- ----- ------#00000001: 99F316C6 43B06508 5BDB89EE => 00411000 0000111F 43C5CF7B 5BDB89EE#00000002: 99F6FCF6 43B075DF 056F5F20 => 00419CF9 000000CA ED58A5AD 056F5F20...#0000002B: 99F5875A 43B07219 B182023B => 0041359C 0000000C 996C48C8 B182023B#0000002C: 99F5375A 43B07219 B05176BB => 00413588 0000000C 983BBC48 B05176BBAlgorithm--------- OffsetRVA decrypting: +6A08E97A, Shld E, ++, bswap Length decrypting: Shrd 18, ++, Shld 18, ~, ^E347219D, +301E1D57, ~, ^77D93621 Hash encrypting: --, --, ~, bswap, +8B45E9E9, --, ~, bswapMemory Check #2 Table=====================Address: 0040D164, Size: 000021CC(000002D1 Items), Table Hash: C8A37D66Item eOffset eLength eHash Decrypting dOffset dLength cHash ceHash----- ------- ------- ----- ------- ------- ----- ------#00000001: BA3B965B 99C2CE3A AB72BDF6 => 00403768 00000007 EEA5E87A AB72BDF6#00000002: BA3B62F3 9CC2CE3A 55DA3F26 => 00406AD0 00000004 01200000 55DA3F26...#00000231: BA3B9899 8DC2CE3A 0552AC2B => 0040352A 00000013 3A5489D0 0552AC2B#00000232: BA3BB96E 9AC2CE3A 9502AE76 => 00401455 00000006 71567840 9502AE76#00000233: BA3BCDC4 61346F34 11058009 => FFFFFFFF <= *** Table End Flag found!Algorithm--------- OffsetRVA decrypting: +45C4323A, ~, --, -- Length decrypting: -A1C2CE3B, bswap, ++, ~ Hash encrypting: ^6153D6ED, -86B3B143, bswap, ~Note: cHash - Hash calculated by getHash handler; ceHash - Encrypted cHash; should == eHash if everythig is fine, else patches or software breakpoints detected.Script:/* Note: run this script at the target entry: 00414699 !!! MistHill at tuts4you.com, 2015/05/25*/ history 0 lclr bphwc bpmc bc var pWinMain var vGetHash var dwModuleBase var pMemoryCheckTable var bufTemp mov pWinMain, 0000102F ; all RVA mov vGetHash, 0000CC9D mov pMemoryCheckTable, 0000D164 gmi eip, MODULEBASE mov dwModuleBase, $RESULT add pWinMain, dwModuleBase add vGetHash, dwModuleBase add pMemoryCheckTable, dwModuleBase bphws pWinMain erun bphwc pWinMain cmp eip, pWinMain jne L_Exit mov [vGetHash-914], #49E8ED0D0000894500# mov [pMemoryCheckTable+18], #59518BD18D89D50D00003B4DFC7507B8667DA3C8EB108D92D973FFFF3B55FC7505B87AE8A5EEC3# mov bufTemp, [pMemoryCheckTable+1A58], 0C mov [pMemoryCheckTable+0C], bufTemp, 0CL_Exit: ret 8
SunBeam Posted May 25, 2015 Author Posted May 25, 2015 ^ *claps* Nothing more to add, straightforward and elegant. BR,Sun
MistHill Posted June 1, 2015 Posted June 1, 2015 @SunBeamThank you for your example making my understanding of things more clear. @AllThe "Random Memory Check" sample can be found in HellSpider's post: [DevirtualizeMe] VMProtect 2.13.5
fresharplite Posted February 13, 2017 Posted February 13, 2017 Who can re-upload the source file! thank you!
BOSCH Posted July 8, 2019 Posted July 8, 2019 Can someone re upload the source file? Thanks in advance.
xtor Posted October 19, 2020 Posted October 19, 2020 Can someone re upload the source file again? Thanks in advance.
SunBeam Posted January 28, 2022 Author Posted January 28, 2022 (edited) Re-uploaded here: https://www.mediafire.com/file/sngpjiclmdgu3m2/Lic_MessageBox_2.rar/file Password: sunbeam Edited January 28, 2022 by SunBeam 1
Teddy Rogers Posted January 28, 2022 Posted January 28, 2022 Now attached to the first post. Thanks for the reupload... Ted.
abbas Posted September 16, 2022 Posted September 16, 2022 On 4/4/2015 at 10:11 AM, White said: Hi, my solution. 0040B53F 8B4424 18 mov eax,dword ptr ss:[esp+0x18] change to 0040B53F 33C0 xor eax,eax 0040B541 B0 01 mov al,0x1 could you please explain how you found this?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now