This is a discussion on Re-release "Item Validator" within the Priston Tale Releases forums, part of the Priston Tale category; Originally Posted by TrAnCe ^^ LOL, so If I make a new item without checksum it will create and validate? ...
░▄▄▄░░▄▄░▄▄░░▄▄░░▄▄▄░
░░█░░███████░█░█░░█░░
░░█░░▀█████▀░█▀░░░█░░
░▄█▄░░░▀█▀░░░█░░░░█░░
would be nice if you could translate all the function to C.. after all you did, I guess it wouldnt be that hard lol
To clarify, this is clear "source code obfuscation".Now dwAddress = 0x44A8A0 so why not write those two linesCode:dwAddress = 0x00D6ECAD; dwAddress = dwAddress ^ 0x0092440D;instead? The compiler optimiser should produce that in assembler anyway.Code:dwAddress = 0x44A8A0;
Yes, I wondered about that as well.Not at all sure about that, but I guess you could write a DLL / LIB to compile in C which incorporates this routine as in-line assembler:-Code:DD ThisHash = 0 DD LastHash = 0 DD Unk1 = 0 DD Unk2 = 0 DD Unk3 = 0 ValidatorMain: ; 0044A8A0(guessed Arg1) push edi call [<&KERNEL32.GetTickCount>] ; [KERNEL32.GetTickCount] mov ecx,[Unk1] mov edi,[esp+8] add eax,ecx mov [edi+4],eax push esi lea esi,[edi+18] mov edx,4 mov dword ptr [ThisHash],0 mov [LastHash],eax call Hash1 lea esi,[edi+1C] mov edx,20 call Hash1 lea esi,[edi+3C] mov edx,4 call Hash1 lea esi,[edi+40] call Hash1 lea esi,[edi+4C] mov edx,10 call Hash1 lea esi,[edi+64] mov edx,4 call Hash1 lea esi,[edi+78] call Hash1 lea esi,[edi+7C] call Hash1 lea esi,[edi+80] call Hash1 lea esi,[edi+68] call Hash1 lea esi,[edi+6C] call Hash1 lea esi,[edi+70] call Hash1 lea esi,[edi+74] call Hash1 lea esi,[edi+84] call Hash1 lea esi,[edi+88] call Hash1 lea esi,[edi+8C] call Hash1 lea esi,[edi+90] call Hash1 lea esi,[edi+94] call Hash1 lea esi,[edi+98] call Hash1 lea esi,[edi+9C] call Hash1 lea esi,[edi+0A0] call Hash1 lea esi,[edi+0A4] call Hash1 lea esi,[edi+0A8] call Hash1 lea esi,[edi+0AC] call Hash1 lea esi,[edi+0B0] call Hash1 lea esi,[edi+0B4] call Hash1 lea esi,[edi+0B8] call Hash1 lea esi,[edi+0BC] call Hash1 lea esi,[edi+0C0] call Hash1 lea esi,[edi+0C4] call Hash1 lea esi,[edi+0C8] call Hash1 lea esi,[edi+0CC] call Hash1 lea esi,[edi+0F4] call Hash1 lea esi,[edi+0F8] mov edx,0DC call Hash1 lea esi,[edi+0E0] mov edx,4 call Hash1 lea esi,[edi+0E4] call Hash1 lea esi,[edi+0E8] mov edx,8 call Hash1 lea esi,[edi+0DC] mov edx,4 call Hash1 lea esi,[edi+0F0] call Hash1 mov eax,[ThisHash] pop esi mov edx,[Unk2] mov [edi+10],eax mov [edi+8],edx mov ecx,[Unk3] mov [edi+1EC],ecx mov ecx,[edi+0D4] test ecx,ecx je Label1 mov ecx,[edi+0D8] test ecx,ecx jne Label2 Label1: mov edx,[edi+4] mov [edi+0D4],edx mov [edi+0D8],eax Label2: push edi xor eax,eax test edx,edx jle EndLoop1 mov ecx,[LastHash] push ebx push edi mov edi,edi Loop1: movsx edi,byte ptr [esi+eax] mov ebx,ecx and ebx,00001FFF inc ebx imul edi,ebx mov ebx,[ThisHash] add ebx,edi inc ecx inc eax cmp eax,edx mov [ThisHash],ebx mov [LastHash],ecx jl Loop1 pop edi pop ebx EndLoop1: mov eax,[ThisHash] push edi push esi mov esi,[esp+8] push esi push ebx mov ebx,[esp+8] mov eax,[ebx+10] mov ecx,[ebx+18] push ebp imul ecx,eax lea ebp,[ebx+18] push esi push edi and ecx,0000F555 lea edi,[ebx+8C] mov esi,4 mov [ThisHash],ecx mov [LashHash],eax call Hash2 lea edi,[ebx+90] call Hash2 lea edi,[ebx+94] call Hash2 lea edi,[ebx+98] call Hash2 lea edi,[ebx+9C] call Hash2 lea edi,[ebx+0A0] call Hash2 lea edi,[ebx+0A4] call Hash2 lea edi,[ebx+0C0] call Hash2 lea edi,[ebx+0C4] call Hash2 lea edi,[ebx+0C8] call Hash2 lea edi,[ebx+0CC] call Hash2 lea edi,[ebx+0F4] call Hash2 lea edi,[ebx+0F8] mov esi,0DC call Hash2 lea edi,[ebx+0E0] mov esi,4 call Hash2 lea edi,[ebx+0E4] call Hash2 lea edi,[ebx+0E8] mov esi,8 call Hash2 lea edi,[ebx+0DC] mov esi,4 call Hash2 lea edi,[ebx+0F0] call Hash2 lea edi,[ebx+3C] call Hash2 lea edi,[ebx+40] call Hash2 lea edi,[ebx+78] call Hash2 lea edi,[ebx+7C] call Hash2 lea edi,[ebx+80] call Hash2 lea edi,[ebx+68] call Hash2 lea edi,[ebx+6C] call Hash2 lea edi,[ebx+70] call Hash2 lea edi,[ebx+74] call Hash2 lea edi,[ebx+84] call Hash2 lea edi,[ebx+88] call Hash2 lea edi,[ebx+4C] mov esi,10 call Hash2 lea edi,[ebx+64] mov esi,4 call Hash2 lea edi,[ebx+0BC] call Hash2 lea edi,[ebx+0A8] call Hash2 lea edi,[ebx+0AC] call Hash2 lea edi,[ebx+0B0] call Hash2 lea edi,[ebx+0B4] call Hash2 lea edi,[ebx+0B8] call Hash2 mov edi,ebp call Hash2 lea edi,[ebx+1C] mov esi,20 call Hash2 mov eax,[ThisHash] pop edi pop esi pop ebp movsx edx,word ptr [ebx+1E4] movsx ecx,word ptr [ebx+1E6] imul edx,edx,7 lea ecx,[ecx*8+ecx] xor ecx,edx mov edx,[ebx+4] xor ecx,eax mov eax,[ebx+1EC] and eax,0000FFFF lea ecx,[eax*4+ecx] mov eax,[ebx+10] add eax,ecx shl eax,0D xor eax,edx xor eax,ecx pop ebx add esp,4 mov [esi+0C],eax mov eax,1 pop esi mov eax,[edi+18] add eax,[edi+10] mov [edi+60],eax mov eax,[Unk1] add esp,8 inc eax mov [Unk1],eax mov eax,1 pop edi ret Hash1: ; Hash1(guessed void) xor eax,eax test edx,edx jle EndHashLoop1 mov ecx,[LastHash] push ebx push edi mov edi,edi HashLoop1: movsx edi,byte ptr [esi+eax] mov ebx,ecx and ebx,00001FFF inc ebx imul edi,ebx mov ebx,[ThisHash] add ebx,edi inc ecx inc eax cmp eax,edx mov [ThisHash],ebx mov [LastHash],ecx jl HashLoop1 pop edi pop ebx EndHashLoop1: mov eax,[ThisHash] ret Hash2: xor eax,eax ; Hash2(guessed void) test esi,esi jle EndHashLoop2 mov edx,[LashHash] push ebx push ebp mov edi,edi HashLoop2: movsx ecx,byte ptr [edi+eax] mov ebx,edx and ebx,00000F57 lea ebp,[ecx+2] add ebx,9 imul ebx,ebp mov ebp,[ThisHash] add ecx,eax imul ecx,ecx,29 add ebp,ebx inc eax cmp eax,esi lea edx,[ecx+edx+29] mov [ThisHash],ebp mov [LashHash],edx jl HashLoop2 pop ebp pop ebx EndHashLoop2: mov eax,[ThisHash] ret
I have some questions about validator's source code. Is the compiled release working correctly?
Item's checksum code are located in two positions inside .ITM file.
I can't find where it's generated and where the validator inserts it on .ITM file.
I also couldn't figure out why the DLL needs to be injected on 4096.exe, as it does nothing with the Hotuk GameServer.
You look at it completely the wrong way around.
It does.Item Validator doesn't do this. It forces the 4096 server to do it.It does (almost) nothing in it's self except present the dialogue, read the file into memory and save it again.
Importantly, what it does between loading and saving the file is to pass a pointer to the loaded data to the checksum routines in the 4096 server.
It also have some values that are "generated" by server.
I disassembled it to TASM syntax and I saw more calls that than. I think current method is "preferable". Clean and easy :)
Btw. if I may ask, how long ago did you got this stuff? Do you have more hidden goodies? :)
I simply would like to know history of this tool, was it invented for some server? Why some "random hack maker" would make tool that is server sided. O_o
░▄▄▄░░▄▄░▄▄░░▄▄░░▄▄▄░
░░█░░███████░█░█░░█░░
░░█░░▀█████▀░█▀░░░█░░
░▄█▄░░░▀█▀░░░█░░░░█░░
Nope. I "broke out" the calls in that translation.
If a "call" is only made once, and not part of a loop which would otherwise become a "long" jump, there is no point in representing it as a function / subroutine in it's own right. Especially if it's parameters are "void".
The thing which worries me most is the Unk1-3 values which are 0 when the image is loaded. In particular, Unk3 is loaded into a register only once, and never written to. If that is how it is designed to work then the register should simply be XORed with it's self. I'm sure some other routine must affect that memory location without being called from, or calling to that routine.
However, if the value is not constant, I can't see how the hash would produce a consistent value either.
Don't know if I did it by the harder way, but I tried to "brute force" the checksum algorithm by getting some sections of .ITM file, XORing with bytes from 0x00 to 0xFF, and generating a crc32 checksum, but got no success on validating a modified item.
Maybe checksums are generated with some formulas like login packet encryption, that doesn't uses a single byte to XOR the whole packet of bytes?
The disassembly looks like a simpler algorithm along similar lines to MD5 to me. The long list of calls to Hash1 or Hash2 are usually written as a Macro when you actually assemble / compile them from source.
As for "better way to do it", if you rebase a PE of your own which calls LoadLibrary to load "4096.exe" at it's normal virtual address, you can make those calls in the server executable without having it running in the background.
The concern about Unk3 still stands in that case though.![]()