Valhalla Legends Forums Archive | Assembly Language (any cpu) | Reversing Skills #2

AuthorMessageTime
iago
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?

[code]   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[/code]



Solution (in plain C this time):
[quote][color=black]void shuffleStarcraftCDKey(char *CDKey)
{
   int i;
   int edi = 0x0b;

   for(i = 0xC2; i >= 7; i -= 0x11)
      swap(&CDKey[edi--], &CDKey[i % 0x0C]);
}[/color][/quote]
March 16, 2004, 2:47 AM
Maddox
Interesting. What does esi contain at the beginning?
March 16, 2004, 4:03 AM
iago
Sorry, I made a mistake typing that. It's fixed and I put <FIX> tags around it.

My bad :)
March 16, 2004, 2:34 PM
Maddox
I don't believe swap() is in the Standard C Library.
March 17, 2004, 2:26 AM
iago
[quote author=Maddox link=board=7;threadid=5807;start=0#msg49962 date=1079490415]
I don't believe swap() is in the Standard C Library.
[/quote]

I forgot to say, in my solution I used a "swap" function I didn't include, you can assume it exists :)
March 17, 2004, 2:32 AM
Maddox
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.
March 17, 2004, 7:18 AM
iago
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.
March 17, 2004, 2:07 PM
Skywing
[quote author=iago link=board=7;threadid=5807;start=0#msg50026 date=1079532432]
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.
[/quote]
Sounds to me like the programmer used int needlessly instead of unsigned. Don't do that!
March 17, 2004, 3:33 PM
iago
[quote author=Skywing link=board=7;threadid=5807;start=0#msg50041 date=1079537638]
[quote author=iago link=board=7;threadid=5807;start=0#msg50026 date=1079532432]
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.
[/quote]
Sounds to me like the programmer used int needlessly instead of unsigned. Don't do that!
[/quote]

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?
March 17, 2004, 4:51 PM
Skywing
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.
March 17, 2004, 4:54 PM
iago
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).
March 17, 2004, 5:28 PM
Kp
[quote author=Skywing link=board=7;threadid=5807;start=0#msg50053 date=1079542440]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.[/quote]

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

[quote author=iago link=board=7;threadid=5807;start=0#msg50058 date=1079544524]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).[/quote]

Java avoids this problem by not even supporting signed types properly! Just try declaring an unsigned 32bit quantity in Java. :)
March 17, 2004, 6:28 PM
iago
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.
March 17, 2004, 6:38 PM
Skywing
[quote author=iago link=board=7;threadid=5807;start=0#msg50069 date=1079548695]
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.

[/quote]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.
March 17, 2004, 9:00 PM
iago
[quote author=Skywing link=board=7;threadid=5807;start=0#msg50115 date=1079557232]
[quote author=iago link=board=7;threadid=5807;start=0#msg50069 date=1079548695]
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.

[/quote]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.
[/quote]

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).
March 17, 2004, 9:08 PM
Adron
[quote author=Maddox link=board=7;threadid=5807;start=0#msg50012 date=1079507891]
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.
[/quote]

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.
March 17, 2004, 9:09 PM
Skywing
[quote author=iago link=board=7;threadid=5807;start=15#msg50120 date=1079557730]
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).
[/quote]
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.
March 17, 2004, 9:15 PM
Adron
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.
March 17, 2004, 9:18 PM
iago
[quote author=Adron link=board=7;threadid=5807;start=15#msg50128 date=1079558304]
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.
[/quote]

Multiplication works out the same in both signed and unsigned, doesn't it?
March 17, 2004, 11:53 PM
Adron
[quote author=iago link=board=7;threadid=5807;start=15#msg50154 date=1079567624]
Multiplication works out the same in both signed and unsigned, doesn't it?
[/quote]

No, multiplication is different for signed and unsigned.
March 17, 2004, 11:58 PM
iago
[quote author=Adron link=board=7;threadid=5807;start=15#msg50159 date=1079567939]
[quote author=iago link=board=7;threadid=5807;start=15#msg50154 date=1079567624]
Multiplication works out the same in both signed and unsigned, doesn't it?
[/quote]

No, multiplication is different for signed and unsigned.
[/quote]

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
[code]#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;
}
[/code]
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.

March 18, 2004, 12:12 AM
Adron
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.
March 18, 2004, 1:33 AM
iago
[quote author=Adron link=board=7;threadid=5807;start=15#msg50183 date=1079573617]
It matters when you use all of the result, i.e. multiplying two 32-bit numbers generates a 64-bit result.
[/quote]

hmm, I've never done or seen that before. How's that work in assembly?
March 18, 2004, 2:46 AM
Adron
Well, a similar example:

[code]
0CBC:0100 mov ax,8001
0CBC:0103 mov dx,ffff
0CBC:0106 imul dx
[/code]

dx = 0, ax = 7fff

[code]
0CBC:0108 mov ax,8001
0CBC:010B mov dx,ffff
0CBC:010E mul dx
[/code]

dx = 8000, ax = 7fff
March 18, 2004, 2:50 AM
iago
Ah, so it works exactly reverse of division, using edx:eax. Neat! :)
March 18, 2004, 4:05 PM

Search