![]() |
| |||||||
| Home | GzP Upload | GzP Arcade | Register | vbBux / vbPlaza | All Albums | FAQ | Donate | Members List | Calendar | Mark Forums Read |
| Maple Story Tutorials Tutorials only. No requests. |
![]() |
| | Thread Tools | Display Modes |
| | #1 |
| Registered User | [RLS][TUT]Mscrc/ggcrc Bypasses This was NOT made by me credits go to XOR but still a thanks would be awesome (I Strongly recommend to Sticky this mods) example bypass for GGCRC is attached at bottom of tut MapleStory's CRC Routine Analysis - Irwin/x0r Since the MapleStory memory integrity routine has been scrutinized lately by many hacking communities I thought it would be fair that I post a 'deep' analysis of it, so there's no more need to rummage through tutorials to see how it works. Since the routine has already been bypassed I won't really focus on where to start, since it has already been bypassed to an extent. Instead I'll just focus on where the community currently is and what the current bypass is doing. The Current Bypass [enable] alloc(newmem,2048) alloc(dump,3670018) // Dump size loadbinary(dump,crc.CEM) // Dump file newmem: cmp ecx,00400000 // Image base jb @f cmp ecx,00780000 // Image end ja @f add ecx, dump-00400000 // Dump offset @@: // Original code mov eax,[ebp+10] push esi push edi jmp 00451cbf 00451cba: jmp newmem // Jump to hook [disable] 00451cba: mov eax,[ebp+10] push esi push edi dealloc(newmem) dealloc(blaaaa) As you can see, the current bypass just checks to see if ECX is within the range of memory to be checked, if it is then it is adjusted to point to the copy of the game's memory which is unmodified. The Inner Workings Of The Bypass The bypass works very simply and is generic per version of MapleStory, only needing to change the game dump when there's a patch of something of that manner, but how does it work? Putting it simply, the bypass utilizes an optimized & modified CRC32 algorithm on the memory, so we can use a PEiD plugin called KANAL to look for generic cryptography signatures: ![]() KANAL's feedback on the analysis of an unpacked cop of MapleStory. 'CRC32b' being the table used for the integrity check. So now we know where the CRC32 table is located, lets have a look at how it is used: ; =============== S U B R O U T I N E ======================================= ; Attributes: bp-based frame ; ULONG __cdecl CalculateCRC32(LPVOID lpStartAddress, SIZE_T nSize, ULONG ulInitialHash, BOOL bUseHash) CalculateCRC32 proc near lpStartAddress = dword ptr 8 nSize = dword ptr 0Ch ulInitialHash = dword ptr 10h bUseHash = dword ptr 14h push ebp mov ebp, esp cmp [ebp+bUseHash], 0 mov ecx, [ebp+lpStartAddress] jz short loc_473980 xor [ebp+ulInitialHash], ecx loc_473980: mov eax, [ebp+ulInitialHash] ; Generic bypass hook-point push esi push edi mov edi, [ebp+nSize] cmp edi, 10h jb loc_473B22 mov esi, edi push ebx shr esi, 4 CalculateCRC: movzx ebx, byte ptr [ecx] mov edx, eax shr edx, 18h xor edx, ebx mov ebx, eax mov eax, ds:CRC32Table[edx*4] shl ebx, 8 xor eax, ebx movzx ebx, byte ptr [ecx+1] mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor edx, eax mov eax, edx shr eax, 18h shl edx, 8 inc ecx movzx ebx, byte ptr [ecx+1] xor eax, ebx mov eax, ds:CRC32Table[eax*4] xor eax, edx inc ecx movzx ebx, byte ptr [ecx+1] mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor edx, eax inc ecx movzx ebx, byte ptr [ecx+1] mov eax, edx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] shl edx, 8 xor eax, edx inc ecx movzx ebx, byte ptr [ecx+1] mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor edx, eax inc ecx movzx ebx, byte ptr [ecx+1] mov eax, edx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] shl edx, 8 xor eax, edx inc ecx movzx ebx, byte ptr [ecx+1] mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] inc ecx movzx ebx, byte ptr [ecx+1] shl eax, 8 xor edx, eax mov eax, edx inc ecx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] movzx ebx, byte ptr [ecx+1] shl edx, 8 xor eax, edx inc ecx mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor edx, eax inc ecx movzx ebx, byte ptr [ecx] mov eax, edx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] movzx ebx, byte ptr [ecx+1] shl edx, 8 xor eax, edx mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor edx, eax inc ecx movzx ebx, byte ptr [ecx+1] mov eax, edx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] shl edx, 8 xor eax, edx inc ecx movzx ebx, byte ptr [ecx+1] mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] inc ecx movzx ebx, byte ptr [ecx+1] shl eax, 8 xor edx, eax inc ecx mov eax, edx shr eax, 18h xor eax, ebx mov eax, ds:CRC32Table[eax*4] movzx ebx, byte ptr [ecx+1] shl edx, 8 xor eax, edx inc ecx mov edx, eax shr edx, 18h xor edx, ebx mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor eax, edx inc ecx sub edi, 10h dec esi jnz CalculateCRC pop ebx loc_473B22: cmp edi, 1 jb short loc_473B41 loc_473B27: movzx esi, byte ptr [ecx] mov edx, eax shr edx, 18h xor edx, esi mov edx, ds:CRC32Table[edx*4] shl eax, 8 xor eax, edx inc ecx dec edi jnz short loc_473B27 loc_473B41: pop edi pop esi pop ebp retn CalculateCRC32 endp This is fairly self-explanitory, the function works in this manner: ULONG __cdecl CalculateCRC32( __in LPVOID lpBuffer, __in SIZE_T nSize, __in_opt ULONG ulInitialHash, __in BOOL bUseInitialHash ); Parameters lpBuffer - The buffer for which the CRC is to be calculated for. nSize - The size of the region to hashed / 16. ulInitialHash - This parameter is only valid if bUseInitialHash is TRUE, ulInitialHash is added to the hash if it is specified. bUseInitialHash - If this parameter is specified then ulInitialHash is added onto the return. Return The function returns the CRC fo the region specified. So now we know how the CRC is calculated, what calls the calculation routine? InitialHash: push ebx push esi xor esi, esi push esi ; bUseHash push esi ; ulInitialHash lea eax, [ebp+lpBuffer] push 2 ; nSize push eax ; lpStartAddress call CalculateCRC32 add esp, 10h mov ebx, eax CalculateHash: mov eax, [edi+1Ch] test eax, eax jz short SendHash cmp esi, [eax-4] jnb short SendHash push 1 ; bUseHash lea eax, [eax+esi*8] push ebx ; ulInitialHash push dword ptr [eax+4] ; nSize push dword ptr [eax] ; lpStartAddress call CalculateCRC32 add esp, 10h mov ebx, eax inc esi jmp short CalculateHash Simple enough, right? The game first generates an initial hash which it then uses on the other hashes, according to the buffer size. The really great thing about this is that even though this is happening, the game calls completely static sizes. So it's very predictable. Creating A Bypass Creating a bypass for this is very easy, as seen with the public variant of the MapleStory CRC bypass. This is however not optimal, instead what you could do is build up a list of possible return CRCs and since the addresses and address sizes are predictable you can simply return the CRC of the region which is being requested instead of creating large dump. I've done this and my CRC lookup table was under 100 kilobytes whilst all generic CRC bypasses I've come across have an average of a 4 megabyte dump, this is a large tradeoff in both speed and size. Expect an example source in the near future, I'm tired as **** at the moment. Last modified: 28 Febuary 2008 07:12:15 __________________________________________________ _____________ GameGuard's CRC Routine Analysis - Irwin/x0r GameGuard has a new function which has been enabled for MapleStory which is essentially a memory integrity check routine. It routinely checks MapleStory's memory and then closes the game if it detects a change. One must think that it was enabled due to the fact that MapleStory's own memory integrity routine was comprised to an unacceptable point. Anyway, it is fairly simple to enable and only needs one setting to be modified, since when GameGuard is loaded the game must call LoadGameGuard("SettingsFile.ini") and in the settings file there is a parameter called GAMECRC, apparently when it is set to '2' it will perform a routine check of MapleStory's memory spanning from the code base to the code end (meaning you can modify dynamic values like the Import Address Table and things of such a manner), here's a copy of MapleStory's INI configuration file: [GAMEMON] GAME_NAME=MapleStoryUS UPDATE_SERVER=gameguard.mapleglobal.com UPDATE_PATH=/nProtect/GameGuard/RealServer/ BACKUP_SERVER=63.251.217.184 BACKUP_PATH=/nProtect/GameGuard/RealServer/ OPTION_VALUE=0 SPEEDCHECK_INTERVAL=1000 SENDERL=1 GAMECRC=2 USE_GGSCAN=1 LOG_SERVER=211.218.237.113 REVISION=47 The Previous Bypass There is currently no public bypass but the previous iteration of the GameGuard CRC routine used the [Only registered and activated users can see links. ] API to read the game's memory and then perform a check to the local copy GameMon.des had. Unfortunately this method has been patched and no longer works. There is more to it than meets the eye however... GameGuard makes copies of all system files which it uses APIs with (e.g. kernel32, ntdll, user32, etc) so that we cannot hook their functions with ease. So instead of normally calling the real APIs they would generate a table of pointers to the functions and call those (reminiscent to a pseudo IAT). Since hooking the copies of these functions isn't really feasible the bypass instead modified the pointer to ReadProcessMemory and made it redirect to their hook. A pseudo bypass hook would work like this: BOOL WINAPI ReadProcessMemoryHook(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) { if ( GetProcessId(hProcess) == dwMapleStoryPID ) { if ( (lpBaseAddress <= 0x00400000) || (lpBaseAddress+nSize >= 0x00800000) ) // See if memory being read is within game's image lpBaseAddress += lpDumpOffset; // Adjust the base address to read the dump instead of the real game memory } return ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead); } Once bypasses started hooking their ReadProcessMemory pointer they decided to drop using ReadProcessMemory directly, their function table still existed however. After GameGuard had patched the GGCRC bypass, their function table entry which held kernel32.ReadProcessMemory now held ntdll.[Only registered and activated users can see links. ], this held no relevance at first but after some members of the community decided to look at how it was used its usage started to become more apparent... Examining GameMon would generally be hard since it is using a very strong packer; Themida. Fortunately GameMon does not utilize Themida too well and the functions are not completely encrypted at run-time. So using a small dumper I coded it is possible to create a dump of GameMon.des whilst it is running. Now when looking at what how NtDeviceIoControl is utilized, it is clearly a function wrapper: /* NTSTATUS NtDeviceIoControlFile( * HANDLE FileHandle, * HANDLE Event, * PIO_APC_ROUTINE ApcRoutine, * PVOID ApcContext, * PIO_STATUS_BLOCK IoStatusBlock, * ULONG IoControlCode, * PVOID InputBuffer, * ULONG InputBufferLength, * PVOID OutputBuffer, * ULONG OutputBufferLength */ ); FileHandle = HANDLE ptr 4 Event = HANDLE ptr 8 ApcRoutine = PIO_APC_ROUTINE ptr 0Ch ApcContext = PVOID ptr 10h IoStatusBlock = PIO_STATUS_BLOCK ptr 14h IoControlCode = ULONG ptr 18h InputBuffer = PVOID ptr 1Ch InputBufferLength = ULONG ptr 20h OutputBuffer = PVOID ptr 24h OutputBufferLength = ULONG ptr 28h mov eax, ds:ServiceIndex test eax, eax jnz short loc_13882 mov eax, ds:ServiceID test eax, eax jnz short loc_13888 loc_13882: jmp ds:NtDeviceIoControlFilePointer ; --------------------------------------------------------------------------- loc_13888: mov eax, ds:ServiceID lea edx, [esp+FileHandle] int 2Eh retn 28h NtDeviceIoControlFile end The NtDeviceIoControlFile wrapper/substitute. This is pretty straight forward, first the wrapper checks to see if the service index is initialized at all, if it isn't it will use the NtDeviceIoControlFile wrapper. If it is, it will then check to see if the individual NtDeviceIoControlFile service is in place, if it is then it will proceed to directly call the service using int 2E, a direct system call (ala SYSENTER). In pseudo-code: NTSTATUS __declspec(naked) NtDeviceIoControlFile( HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength ) { if ( (ServiceIndex == 0) && (ServiceID == 0)) _asm jmp [NtDeviceIoControlFilePointer]; else _asm { mov eax, [ServiceID] lea edx, [esp+FileHandle] int 0x2E retn 0x28 } } So now we must look at what uses it. After some quick snooping it's clear that one of these not only matches the preparation of a read function, it takes the exact same parameters as ReadProcessMemory. So now lets look at the ReadProcessMemory Clone... ; =============== S U B R O U T I N E ======================================= ; Attributes: bp-based frame ; BOOL WINAPI ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten) ReadProcessMemory proc near var_6FC = byte ptr -6FCh var_138 = byte ptr -138h var_34 = dword ptr -34h InputBuffer = byte ptr -30h OutputBuffer = byte ptr -10h hProcess = dword ptr 8 lpBaseAddress = dword ptr 0Ch lpBuffer = dword ptr 10h nSize = dword ptr 14h lpNumberOfBytesWritten= dword ptr 18h push ebp mov ebp, esp push 0FFFFFFFFh push offset SEH_15440 mov eax, fs:SEH push eax mov fs:SEH, esp sub esp, 6F0h push ebx push esi push edi push offset unk_4C5730 mov [ebp+var_34], offset unk_4C5730 nop call near ptr 77722E69h xor ecx, ecx mov dword ptr [ebp+OutputBuffer+0Ch], ecx push eax mov eax, [ebp+4] mov [ebp-1Ch], eax pop eax mov eax, ds:dword_4B1664 cmp eax, 0FFFFFFFFh jz loc_155AE mov ebx, [ebp+lpBaseAddress] mov esi, [ebp+nSize] mov dword ptr [ebp+OutputBuffer], ecx ; nSize mov ecx, [ebp+lpBuffer] mov dword ptr [ebp+InputBuffer+8], ecx ; lpBuffer mov ecx, ds:dword_4B1668 lea edx, [ebx+esi] mov edi, [ebp+hProcess] add ecx, edx push 4 ; OutputBufferLength mov ds:dword_4B1668, ecx lea ecx, [ebp+OutputBuffer] push ecx ; OutputBuffer lea edx, [ebp+InputBuffer] push 20 ; InputBufferLength push edx ; InputBuffer lea ecx, [ebp-18h] push 84020044h ; IoControlCode push ecx ; IoStatusBlock push 0 ; ApcContext push 0 ; ApcRoutine push 0 ; Event push eax ; FileHandle mov dword ptr [ebp+InputBuffer], ebx ; lpBaseAddress mov dword ptr [ebp+InputBuffer+4], esi ; nSize mov dword ptr [ebp+InputBuffer+0Ch], esi mov dword ptr [ebp+InputBuffer+10h], edi ; hProcess call NtDeviceIoControlFile ;-------------------- It's now apparent that there is a structure of sorts being passed on through IOCTL 0x84020044, this is the memory check function without a doubt... but how is it structured? (Note: this is updated, since the version of GameMon I analyzed is now outdated) Entry Usage Offset lpBaseAddress The base address from which to read memory from. 0 hProcess A handle to the process which is to have its memory read. 4 lpBuffer The buffer to recieve the read memory. 16 This along with knowing that the first DWORD in the OutputBuffer is actually the number of bytes to copy allows us to effectively detour and reroute any memory being read.Creating A Bypass Creating a bypass for this is easy to do. All you need to do is locate the pointers for the service index & ID and make sure they stay NULL, since it will always call the user-mode alternative if you do so. Then all you need to do is modify the pointer for NtDeviceIoControl and then modify the memory being read. An example bypass is attached. Last modified: 27 February 2008 18:22:01 Last edited by Spily; 02-28-2008 at 07:40 PM. |
| | |
| The Following 5 Users Say Thank You to Spily For This Useful Post: | 0xMarvel (03-06-2008), bankaiblack (03-30-2008), Cloei (03-02-2008), Stumpy (03-01-2008), xsucazax (03-29-2008) |
| Sponsored Links |
| |
| | #2 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses so.... how would u use this? is this the actual bypass that would work? megazero added 4 Minutes and 5 Seconds later...< --- Please use the edit button in the future--- > Service load: 0% 100% File: bypass.zip Status: OK MD5: c0f9b5782d12491d9a3afc872432be7f Packers detected: - Bit9 reports: File not found Scanner results Scan taken on 29 Feb 2008 05:53:00 (GMT) A-Squared Found nothing AntiVir Found nothing ArcaVir Found nothing Avast Found nothing AVG Antivirus Found nothing BitDefender Found nothing ClamAV Found nothing CPsecure Found nothing Dr.Web Found nothing F-Prot Antivirus Found nothing F-Secure Anti-Virus Found nothing Fortinet Found nothing Ikarus Found nothing Kaspersky Anti-Virus Found nothing NOD32 Found nothing Norman Virus Control Found nothing Panda Antivirus Found nothing Rising Antivirus Found nothing Sophos Antivirus Found nothing VirusBuster Found nothing VBA32 Found nothing Last edited by megazero; 02-28-2008 at 09:58 PM. Reason: Automerged Doublepost |
| | |
| | #3 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses This isn't the bypass itself just follow the tutorial it doesn't even take that long once you make the 2 bypasses you can use VBCE and you're ready to hack |
| | |
| | #4 |
| GzP's Eruruu ![]() ![]() | Re: [RLS][TUT]Mscrc/ggcrc Bypasses If it's working, and you are planning to update it regularly and provide support on it, i'd gladly sticky it.
__________________ ![]() siggy <3 kurisu |
| | |
| | #5 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses For the people who are here to simply take the "bypass" and say "Thanks"- This ISN'T the bypass. This is a tutorial that is there to help you create YOUR OWN bypass. Yes, that's right, I said to create YOUR OWN bypass. There's work involved. What a bummer right? Well, as I mentioned earlier, this is a tutorial to help you create your own bypass. Fairly simple. Though I still have to give credits to xOr, props to you for bringing it to GZP. I don't really follow the hacking community anymore, but still. Nice Work. -Couch3ater |
| | |
| | #6 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses Ty for stickying this i will be updating it whenever it needs to be updated and i'm willing to help the few who are willing to learn |
| | |
| | #8 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses |
| | |
| | #9 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses |
| | |
| | #10 |
| Registered User | Re: [RLS][TUT]Mscrc/ggcrc Bypasses I didn't steal this from Xor as you can see all credits went to him. Go die. |
| | |
| The Following 3 Users Say Thank You to Spily For This Useful Post: |
![]() |
| Bookmarks |
| Thread Tools | |
| Display Modes | |
| |