Hello ASM Community!

I always struggle with topic titles...

Im hoping you guys could help me out a little, im stuck with some snippets of code.

For the past 3 years i have been slowly teaching myself the ASM language, with no prior programming knowledge. Im not learning by writing applications, but rather researching and disassembling executables, mostly games. Now and then i come across something that i have to really look into a learn the in's and out's of, and the examples below have been cracking my skull for the past month.

I know these mnemonics, but never had to deal with them directly. SHL and SHR i have trouble understanding, yet i know they shift at a binary level, and the others are, eg. lea esi, , i know LEA, but the calculation afterwords i am struggling with.

Here are three examples of the logics im researching, from the games code;

;this one moves down the {array} where each structure type is 0x28 in size. So {var_int}=0 is 0x0 is base, {var_int}=1 is 0x28, {var_int}=2 is 0x50 etc.
mov    ebp, {var_int}
lea     esi,
shl     esi, 3
lea     ebx, {array_ptr}


;this one moves down the {array} where each structure type is 0x68 in size. So {var_int}=0 is 0x0 is base, {var_int}=1 is 0x68, {var_int}=2 is 0xD0 etc.
mov    edi, {var_int}
lea     eax,
lea     esi,
shl     esi, 3
lea     ebx, {array_ptr}


;this one moves down the {array} where each structure type is 0x70 in size. So {var_int}=0 is 0x0 is base, {var_int}=1 is 0x70, {var_int}=2 is 0xE0 etc.
mov    edi, {var_int}
lea      esi, ds:0
sub     esi, edi
shl      esi, 4
lea     ebx, {array_ptr}


I dont quite understand how these are going from a input integer to large number, something is throwing me off...

I would appreciate any help regarding this.

Thanks!

-ConceptDroid
Posted on 2009-12-02 16:46:17 by ConceptDroid
Go through the code line by line and try heavily commenting it until you understand it


;this one moves down the {array} where each structure type is 0x28 in size. So {var_int}=0 is 0x0 is base, {var_int}=1 is 0x28, {var_int}=2 is 0x50 etc.

mov    ebp, {var_int}
;; ebp = var_int

lea    esi,
;; esi = var_int + var_int * 4 = var_int * 5

shl    esi, 3 ;; shift 3 bits left = multiply by 8
;; esi = 8 * (var_int * 5) = var_int * 40

lea    ebx, {array_ptr}
;; ebx = array_ptr + var_int * 40
;; 40 decimal = 0x28 hex


The code is just an obfuscation of ebx = array_ptr + var_int * 40.
It's done as an optimization because multiplication (MUL) in ASM is a costly operation. So if you can avoid a MUL by using a 1 or 2 faster instructions like LEA and SHL then your code will run faster.

Here's the more direct version of the code

MOV    eax, {var_int}
MOV    ecx, 40
MUL    ecx ;; eax = var_int * 40
LEA      ebx, {array_ptr}
Posted on 2009-12-02 17:53:45 by r22

Go through the code line by line and try heavily commenting it until you understand it


;this one moves down the {array} where each structure type is 0x28 in size. So {var_int}=0 is 0x0 is base, {var_int}=1 is 0x28, {var_int}=2 is 0x50 etc.

mov    ebp, {var_int}
;; ebp = var_int

lea     esi,
;; esi = var_int + var_int * 4 = var_int * 5

shl     esi, 3 ;; shift 3 bits left = multiply by 8
;; esi = 8 * (var_int * 5) = var_int * 40

lea     ebx, {array_ptr}
;; ebx = array_ptr + var_int * 40
;; 40 decimal = 0x28 hex


The code is just an obfuscation of ebx = array_ptr + var_int * 40.
It's done as an optimization because multiplication (MUL) in ASM is a costly operation. So if you can avoid a MUL by using a 1 or 2 faster instructions like LEA and SHL then your code will run faster.

Here's the more direct version of the code

MOV    eax, {var_int}
MOV    ecx, 40
MUL     ecx ;; eax = var_int * 40
LEA      ebx, {array_ptr}



Thanks for replying!

It seems im having problems understanding the, eg. calculations, aswell as i dont see how SHL its multplying by 8.

Say, if EBP was 3, (I gather in this example you ignore the +0 here) LEA ESI, = 3 + 3 * 4 = 15d, then SHL ESI, 3 = 15 * 8 = 78d??...
Posted on 2009-12-03 05:39:15 by ConceptDroid
Say, if EBP was 3, (I gather in this example you ignore the +0 here) LEA ESI, = 3 + 3 * 4 = 15d, then SHL ESI, 3 = 15 * 8 = 78d??...


15 * 8 = 120 (*** not 78 ***)

SHL
Binary math uses powers of 2.

0001b = 1 = 0x01
If we shift left by 2 bits
0100b = 4 = 0x04
Because shift left by 2 bits is like multiplying by 4 (2^2 = 4)


LEA
Perhaps you should RTM (read the manual). The LEA opcode has 5 parameters

LEA A,
;; A = Any register
;; B = Any register or 0
;; C = Any register or 0
;; D = 2^0 or 2^1 or 2^2 or 2^3 (1 or 2 or 4 or 8)
;; E = A memory address 0 to 4.29~billion

Posted on 2009-12-03 08:06:33 by r22

EBP+EBP*4+0 = EBP*4 + EBP + 0 = 5 * EBP + 0 = 5 * EBP :)

Basically, this is how you multiply something by 5. It's usually faster than using mul.

calculations, aswell as i dont see how SHL its multplying by 8.

1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
5 = 00000101
6 = 00000110
7 = 00000111
8 = 00001000

Let's take 3: 00000011
Let's shoft it 1 place to the left. We get 00000110, which is 6.
Posted on 2009-12-03 08:37:14 by ti_mo_n

It seems im having problems understanding the, eg. calculations, aswell as i dont see how SHL its multplying by 8.


Shifting left once is the same as multiplying times two, twice is times four, three times is times eight, etc.

In short, we are utilizing a known characteristic of the binary number system for efficiency. To calculate a shift's effect mathematically, use 2^x where x is the number of bits you want to shift; left for multiplication and right for division.

I would recommend studying more on binary and powers-of-two.
Posted on 2009-12-03 13:01:10 by SpooK
It's not just binary, any number system can multiply by shifting. A decimal number can be shifted to the left to multiply by 10. Twice to multiply by 100 and so on. In hex you can multiply by factors of 16 and in Oct you can multiply by factors of 8. It should come as no surprise you can multiply or divide by 2 when shifting binary numbers.

Spara

Posted on 2009-12-04 06:10:40 by Sparafusile