Here's a little assembly, can you get the original C or C++ code back?
Note that this is a __fastcall function with a single char* parameter passed in ecx.
BOOL __fastcall func(char *param);
It's a 13-character null-terminated String with every character in the range [0-9].
(Note: none of the registers are preserved, I just skipped over preservation)
----------------------------------------
mov eax, 3
mov esi, ecx
mov ebp, edx
xor ecx, ecx
Top:
movsx edx, byte ptr [ecx+esi]
sub edx, 30h
lea edi, [eax+eax]
xor edx, edi
add eax, edx
inc ecx
cmp ecx, 0Ch
jl short Top
xor edx, edx
mov ecx, 0Ah
div ecx
movsx eax, byte ptr [esi+0Ch]
movsx edx, dl
add edx, 30h
cmp eax, edx
jnz bottom
mov eax, 1
retn 8
bottom:
xor eax, eax
retn 8
----------------------------------------
Solution (in C++):
Quotebool verifyStarcraftCDKey(char *cdkey)
{
int accum = 3;
for(int i = 0; i < 13; i++)
accum += ((cdkey - '0') ^ (accum * 2));
return ((accum % 10) == (cdkey[13] - '0'));
}
Exact C code? Or just the same functionality?
Anyways, I suggest not posting the answer in this thread. Maybe people should PM you the answer.
Edit: Ok, done reversing. :) PM'd iago.
I don't understand the point of rewriting these kind of functions in C when they will probably be slower, and especially when you can use inline assembly.
If I were really going to use this, I probably would leave it like this.
BOOL __declspec(naked) __fastcall func_asm(char *param)
{
__asm
{
pushad
mov eax, 3
mov esi, ecx
xor ecx, ecx
Top:
movsx edx, byte ptr [ecx+esi]
sub edx, 30h
lea edi, [eax+eax]
xor edx, edi
add eax, edx
inc ecx
cmp ecx, 0Ch
jl Top
xor edx, edx
mov ecx, 0Ah
div ecx
movsx eax, byte ptr [esi+0Ch]
movsx edx, dl
add edx, 30h
cmp eax, edx
jnz bottom
popad
mov eax, 1
ret
bottom:
popad
xor eax, eax
ret
}
}
Assembly != portability. I use Linux 30% of the time. And, I'm going to convert this to Java.
Incidentally, stop spamming me with IM's. 3! :P
Anyway, I found that it's easiest to first do it like in his example, then convert them exactly to C, then to cut down the code until there's no redundant statements.
Quote from: iago on March 15, 2004, 08:23 AMAssembly != portability. I use Linux 30% of the time. And, I'm going to convert this to Java.
Assembly is quite portable within an ISA. :) If you're using an x86 based Linux, you can take the assembly with you very easily. For reasons of personal prejudice, I recommend against doing emulations in Java if it can be avoided. Some of the things that are needed just don't work right/well (for instance, try doing an efficient CheckRevision in Java :)).
Quote from: Kp on March 15, 2004, 08:58 AM
(for instance, try doing an efficient CheckRevision in Java :)).
With a little help from Skywing, I got CheckRevision to run on Starcraft in ~100ms in Java.
For 100 runs:
Total time: 9682ms
Average time: 96ms
Min time: 76ms
Max time: 547ms
Quote from: iago on March 15, 2004, 09:46 AMWith a little help from Skywing, I got CheckRevision to run on Starcraft in ~100ms in Java.
I'm honestly impressed. I expected performance much more similar to VB, which just does absolutely horribly with it iirc. How long was your code that implements it? I'd consider it a bit cheating if you got this speed just by unrolling all possible combinations of the version check. :)
Quote from: Kp on March 15, 2004, 10:32 AM
Quote from: iago on March 15, 2004, 09:46 AMWith a little help from Skywing, I got CheckRevision to run on Starcraft in ~100ms in Java.
I'm honestly impressed. I expected performance much more similar to VB, which just does absolutely horribly with it iirc. How long was your code that implements it? I'd consider it a bit cheating if you got this speed just by unrolling all possible combinations of the version check. :)
Haha, me and skywing talked about that :)
The code is very similar to Yobgul's public one (http://botdev.valhallalegends.com/files/checkrevision.zip), except I changed the initial parsing a little. The actual running is pretty much the same as his.
When I actually get this bot working, I'll make it open source, just to prove that bots can be done in Java :)
[edit] I posted it on the Java forum.
Quote from: iago on March 15, 2004, 09:46 AM
Quote from: Kp on March 15, 2004, 08:58 AM
(for instance, try doing an efficient CheckRevision in Java :)).
With a little help from Skywing, I got CheckRevision to run on Starcraft in ~100ms in Java.
For 100 runs:
Total time: 9682ms
Average time: 96ms
Min time: 76ms
Max time: 547ms
What's the fastest way to perform CheckRevision? I'm assuming calling CheckRevision from the ver DLLs would be the fastest -- am I wrong? (If so, explain :P)
Quote from: UserLoser. on March 15, 2004, 07:10 PM
Quote from: iago on March 15, 2004, 09:46 AM
Quote from: Kp on March 15, 2004, 08:58 AM
(for instance, try doing an efficient CheckRevision in Java :)).
With a little help from Skywing, I got CheckRevision to run on Starcraft in ~100ms in Java.
For 100 runs:
Total time: 9682ms
Average time: 96ms
Min time: 76ms
Max time: 547ms
What's the fastest way to perform CheckRevision? I'm assuming calling CheckRevision from the ver DLLs would be the fastest -- am I wrong? (If so, explain :P)
Like Kp said, "...unrolling all possible combinations of the version check."
Or compiling the check revision code into assembly and running it. I believe that's the way the vercheck dlls, although I heard somewhere that those leak memory.
There are several ways to do it, each with their own bonuses and drawbacks.
1) YobGuls' code -- very portable, but not very efficient.
2) BNLS -- very portable, but you suffer network latency and require a BNLS authentication
3) Calling IX86Ver?.dll -- Win32 specific and requires either memory patching the DLL or enduring memory leaks.
4) Performing the revision using a method Skywing designed (which, with my modifications, is used in BNLS afaik)
5) Unrolling all possible combinations of the version check. This is theoretically slightly faster even than the method that we use internally, but requires a tremendous amount of space to account for all possible combinations.
In all cases, you can gain a slight performance boost (if you reconnect frequently anyway) by keeping the files memory mapped for the duration of execution, rather than loading them on-demand (and thereby incurring all mapping overhead every time).
Quote from: Kp on March 15, 2004, 07:51 PM
4) Performing the revision using a method Skywing designed (which, with my modifications, is used in BNLS afaik)
Very descriptive.
Quote from: Maddox on March 15, 2004, 08:01 PMVery descriptive.
His design, his call whether to explain how it works.
TestBNCS compiles the version check formula and then runs it. This is the fastest way of doing it, and is the method used by the vercheck DLLs. Mine runs in about 11-15ms, depending on the other things my machine is doing. That doesn't include the time taken to map the hash files into memory. That also doesn't include cache optimisations which I think might improve the speed by a few ms - something I've been meaning to test but never got round to.
(on topic)
The solution for this is
BOOL __fastcall funcc(char *param)
{
int i = 0, eax = 3, edx;
while(i < 0x0c)
eax += (param[i++] - 0x30) ^ (eax + eax);
edx = (eax % 0x0a) + 0x30;
if(edx == param[0x0c])
return 1;
return 0;
}
Quote from: Maddox on March 15, 2004, 10:13 PM
(on topic)
The solution for this is
BOOL __fastcall funcc(char *param)
{
int i = 0, eax = 3, edx;
while(i < 0x0c)
eax += (param[i++] - 0x30) ^ (eax + eax);
edx = (eax % 0x0a) + 0x30;
if(edx == param[0x0c])
return 1;
return 0;
}
You do realize that I posted the solution in my initial post in a black quote box? :P
<edit> and, I like my solution better. for > while :P
Hah, I never noticed that. :o
Quote
The code is very similar to Yobgul's public one (http://botdev.valhallalegends.com/files/checkrevision.zip), except I changed the initial parsing a little. The actual running is pretty much the same as his.
Who is YobGuls? I've never heard of him before until I started coding for Battle.net which has no only been two weeks when I tested out his hashing algorithm and check revision.
Quote from: Mephisto on March 16, 2004, 08:57 PM
Quote
The code is very similar to Yobgul's public one (http://botdev.valhallalegends.com/files/checkrevision.zip), except I changed the initial parsing a little. The actual running is pretty much the same as his.
Who is YobGuls? I've never heard of him before until I started coding for Battle.net which has no only been two weeks when I tested out his hashing algorithm and check revision.
He's some ancient and powerful person in battle.net's history.
The only program I ever saw from YobGuls was a stand-alone d2 gamebot that didn't get very far.
Is he still around?
Probably. I wouldn't be surprised if he's a member of vL under a different name. *looks around suspiciously*
^^
Quote from: iago on March 17, 2004, 08:07 AM
Probably. I wouldn't be surprised if he's a member of vL under a different name. *looks around suspiciously*
I don't know, but I don't think so. He was clever and good at reversing, but he wrote simple code. He didn't refine it as much as we did. He renewed bot making by being the first person to widely publicly post the results of his reversing. As far as I know, he dove into it for a limited time and then got bored. I think he was more skilled as a hacker/reverser than as a programmer.
By the way, I noticed a little problem with your original asm code:
Quote from: iago on March 14, 2004, 06:23 PM
--snip--
mov eax, 1
retn 8
bottom:
xor eax, eax
retn 8
Isn't it a tad unusual for a __fastcall function with only 1 param to be returning 8 bytes to the stack?
~Death_Ryder
I think there was a second parameter, but it was irrelevant for that.
I thought fastcall didn't even use the stack. I thought it used registers for passing arguements to functions. I could be wrong and correct me if I am.
The first 2 parameters are ecx/edx, after that they are done like stdcall.
Quote from: iago on March 27, 2004, 11:00 AM
The first 2 parameters are ecx/edx, after that they are done like stdcall.
In your previous post you meant to say "third."
Fine!! "I think there was a second stack parameter" is what I meant.
Go away :P
What was the first stack parameter then? :P
Irrelevant!
int __fastcall DecodeStarcraftKey(char *CDKeyCopy,int *product,int *CDKeyVal2,int *CDKeyVal1)