Valhalla Legends Archive

Programming => General Programming => Assembly Language (any cpu) => Topic started by: iago on March 15, 2004, 08:47 PM

Title: Reversing Skills #2
Post by: iago on March 15, 2004, 08:47 PM
This is the same as the one above.  13-digit parameter is stored as a char* pointed at by <FIX>esi</FIX>.  Can you convert this to C?

   lea     edi, [esi+0Bh]
   mov     ecx, 0C2h      
top:                            
   mov     eax, ecx        
   mov     ebx, 0Ch        
   cdq                    
   idiv    ebx
   mov     al, [edi]      
   sub     ecx, 11h        
   dec     edi            
   cmp     ecx, 7          
   mov     bl, [edx+esi]  
   mov     [edi+1], bl    
   mov     [edx+esi], al  
   jge     top




Solution (in plain C this time):
Quotevoid shuffleStarcraftCDKey(char *CDKey)
{
   int i;
   int edi = 0x0b;

   for(i = 0xC2; i >= 7; i -= 0x11)
      swap(&CDKey[edi--], &CDKey[i % 0x0C]);
}
Title: Re:Reversing Skills #2
Post by: Maddox on March 15, 2004, 10:03 PM
Interesting. What does esi contain at the beginning?
Title: Re:Reversing Skills #2
Post by: iago on March 16, 2004, 08:34 AM
Sorry, I made a mistake typing that.  It's fixed and I put <FIX> tags around it.

My bad :)
Title: Re:Reversing Skills #2
Post by: Maddox on March 16, 2004, 08:26 PM
I don't believe swap() is in the Standard C Library.
Title: Re:Reversing Skills #2
Post by: iago on March 16, 2004, 08:32 PM
Quote from: Maddox on March 16, 2004, 08:26 PM
I don't believe swap() is in the Standard C Library.

I forgot to say, in my solution I used a "swap" function I didn't include, you can assume it exists :)
Title: Re:Reversing Skills #2
Post by: Maddox on March 17, 2004, 01:18 AM
I got the same solution as you iago. It looks like cdq is just there to set edx = 0. What's the advantage of this over xor edx, edx? I've seen the cdq - idiv combination several times.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 08:07 AM
I'm guessing that using cdq before a division is standard.  That's the first time I seen it, but that's perfectly logical.

One thing is, say eax is negative.  The cdq will make sure that the div uses the negative number and not the equivolant positive.  The sign extension is important.

I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Title: Re:Reversing Skills #2
Post by: Skywing on March 17, 2004, 09:33 AM
Quote from: iago on March 17, 2004, 08:07 AM
I'm guessing that using cdq before a division is standard.  That's the first time I seen it, but that's perfectly logical.

One thing is, say eax is negative.  The cdq will make sure that the div uses the negative number and not the equivolant positive.  The sign extension is important.

I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Sounds to me like the programmer used int needlessly instead of unsigned.  Don't do that!
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 10:51 AM
Quote from: Skywing on March 17, 2004, 09:33 AM
Quote from: iago on March 17, 2004, 08:07 AM
I'm guessing that using cdq before a division is standard.  That's the first time I seen it, but that's perfectly logical.

One thing is, say eax is negative.  The cdq will make sure that the div uses the negative number and not the equivolant positive.  The sign extension is important.

I know that this number *can't possibly* be negative, so it would be no change (and perhaps an optimization) to do xor edx, edx, but that wouldn't always work.
Sounds to me like the programmer used int needlessly instead of unsigned.  Don't do that!

I suspect it was stored as a char*, so he put it into a char then did the arithmatic on it.  If he had used an unsigned char, he would have had to cast it to that.  

Which brings up an interesting question: why ARE chars signed by default?
Title: Re:Reversing Skills #2
Post by: Skywing on March 17, 2004, 10:54 AM
They aren't.  The signedness of char is implementation-defined, which is even worse.  You can't rely on it being either signed or unsigned (unless explicitly qualifying the signed-ness; then again, signed char* is incompatible with char* which is incompatible with unsigned char*, so you have ugly casts needed for all stdlib string functions).

cl.exe provides a command-line switch to set the default char to act unsigned (it's default is signed).  I don't know about any other compilers, though.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 11:28 AM
That's eww.  We should all start using Java which uses wide characters by default (I screwed up a few times assuming that sizeof(char) == 1).
Title: Re:Reversing Skills #2
Post by: Kp on March 17, 2004, 12:28 PM
Quote from: Skywing on March 17, 2004, 10:54 AMcl.exe provides a command-line switch to set the default char to act unsigned (it's default is signed).  I don't know about any other compilers, though.

gcc also has a switch for controlling this: -fsigned-char and -funsigned-char.

Quote from: iago on March 17, 2004, 11:28 AMThat's eww.  We should all start using Java which uses wide characters by default (I screwed up a few times assuming that sizeof(char) == 1).

Java avoids this problem by not even supporting signed types properly!  Just try declaring an unsigned 32bit quantity in Java. :)
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 12:38 PM
Why would you ever have to?  Well, the only time I've ever seen a need is in division.  Java can do unsigned shifting in much the same was as assembly: different operator.
Title: Re:Reversing Skills #2
Post by: Skywing on March 17, 2004, 03:00 PM
Quote from: iago on March 17, 2004, 12:38 PM
Why would you ever have to?  Well, the only time I've ever seen a need is in division.  Java can do unsigned shifting in much the same was as assembly: different operator.

Probably because unsigned numbers are (rightly) used all the time in The Rest Of The World, and despite Sun's best attempts, Java can't completely ignore reality.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 03:08 PM
Quote from: Skywing on March 17, 2004, 03:00 PM
Quote from: iago on March 17, 2004, 12:38 PM
Why would you ever have to?  Well, the only time I've ever seen a need is in division.  Java can do unsigned shifting in much the same was as assembly: different operator.

Probably because unsigned numbers are (rightly) used all the time in The Rest Of The World, and despite Sun's best attempts, Java can't completely ignore reality.

But,what would you need an unsigned number for that a signed number + unsigned operators can't handle?  

In writing the functions to log onto battle.net (check revision, cdkey decode, broken sha-1) I never had to do anything weird to shift variables besides use the unsigned shift operator rather than the signed one (like assembly does).
Title: Re:Reversing Skills #2
Post by: Adron on March 17, 2004, 03:09 PM
Quote from: Maddox on March 17, 2004, 01:18 AM
I got the same solution as you iago. It looks like cdq is just there to set edx = 0. What's the advantage of this over xor edx, edx? I've seen the cdq - idiv combination several times.

It is standard to use cdq before idiv because idiv means signed division. It is standard to use xor before div because div means unsigned division. You should never see cdq div or xor idiv.
Title: Re:Reversing Skills #2
Post by: Skywing on March 17, 2004, 03:15 PM
Quote from: iago on March 17, 2004, 03:08 PM
But,what would you need an unsigned number for that a signed number + unsigned operators can't handle?  

In writing the functions to log onto battle.net (check revision, cdkey decode, broken sha-1) I never had to do anything weird to shift variables besides use the unsigned shift operator rather than the signed one (like assembly does).
You would need to support unsigned numbers to do lots of things (or go to a lot of [performance-degrading] trouble to work around it).  For instance, sequence numbers in lots of network protocols are unsigned, and there are many file formats with unsigned numbers.  In fact, if you were ever to try and process a .mpq file you downloaded from Battle.net within Java, you would probably run into problems with no unsigned support.
Title: Re:Reversing Skills #2
Post by: Adron on March 17, 2004, 03:18 PM
If you have all the unsigned operators available, then sure, you can use unsigned multiplication, unsigned division etc when they are needed, but it's a pain to remember to use the right multiplication operator every time compared to defining the signedness of a variable correctly once.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 05:53 PM
Quote from: Adron on March 17, 2004, 03:18 PM
If you have all the unsigned operators available, then sure, you can use unsigned multiplication, unsigned division etc when they are needed, but it's a pain to remember to use the right multiplication operator every time compared to defining the signedness of a variable correctly once.

Multiplication works out the same in both signed and unsigned, doesn't it?
Title: Re:Reversing Skills #2
Post by: Adron on March 17, 2004, 05:58 PM
Quote from: iago on March 17, 2004, 05:53 PM
Multiplication works out the same in both signed and unsigned, doesn't it?

No, multiplication is different for signed and unsigned.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 06:12 PM
Quote from: Adron on March 17, 2004, 05:58 PM
Quote from: iago on March 17, 2004, 05:53 PM
Multiplication works out the same in both signed and unsigned, doesn't it?

No, multiplication is different for signed and unsigned.

I can't think of any situation where that would happen, and I remember my digital logic prof explaining to us why, so I wrote a quick program to test it
#include <stdio.h>
int main()
{
       for(int i = -10; i < 10; i++)
       {
               for(int j = -10; j < 10; j++)
               {
                       int a = i;
                       int b = j;
                       unsigned int c = i;
                       unsigned int d = j;

                       if((int)(a*b) != (int)(c*d))
                               printf("doesn't match at %d %d", i, j);
               }
       }

       return 0;
}

It outputs nothing.  Can you come up with a case where it wouldn't?  I'm testing both positive and negative numbers in every combination.

Title: Re:Reversing Skills #2
Post by: Adron on March 17, 2004, 07:33 PM
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.
Title: Re:Reversing Skills #2
Post by: iago on March 17, 2004, 08:46 PM
Quote from: Adron on March 17, 2004, 07:33 PM
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.

hmm, I've never done or seen that before.  How's that work in assembly?
Title: Re:Reversing Skills #2
Post by: Adron on March 17, 2004, 08:50 PM
Well, a similar example:


0CBC:0100 mov ax,8001
0CBC:0103 mov dx,ffff
0CBC:0106 imul dx


dx = 0, ax = 7fff


0CBC:0108 mov ax,8001
0CBC:010B mov dx,ffff
0CBC:010E mul dx


dx = 8000, ax = 7fff
Title: Re:Reversing Skills #2
Post by: iago on March 18, 2004, 10:05 AM
Ah, so it works exactly reverse of division, using edx:eax.  Neat! :)