L ZZZZZZ RRRRR SSSSS L Z R R S L aaa Z aaa R R u u S L a Z a RRRRR u u SSSSS XX L aaaa Z aaaa R R u u S XXXX L a a Z a a R R u u S XXXXXX LLLLLLL aaaaa ZZZZZZZ aaaaa R R uuuuu SSSSSS XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXX XXXXXX XXXX proudly presents his 37.Cracking Tutorial (16.03.2000) XX Assembly for Crackers II (new edition of Corn2's A.f.C) I. Introduction II. The essay III. BTW I. Introduction One of the most common problems for newbies is understanding better what happens in the code they currently trace through. This is mostly, because they have no, or only a small knowledge about the assembler mmnemonics that come and go on the SoftIce screen. This tut should help newbies to understand the *basic* assembly instructions, so that they can understand the code better. The title "Assembly for Crackers II" should not be seen as a kind of blasphemy (when I put myself on Corn2's level) but more to honor Corn2's essay "Assembly for Crackers" from 1997 which was one of the essays I learned all this cracking stuff from. ;) (Mex/C4N '97) which were available from quantico.tsx.org (seems down these days, but I don't know for how long) II. The essay OK, let's start with a general introduction to registers and flags. Registers: On the average WinTel CPU you have 9 32bit registers (w/o flag registers). Their names are eax : Extended Accumulator Register ebx : Extended Base Register ecx : Extended Counter Register edx : Extended Data Register esi : Extended Source Index edi : Extended Destination Index ebp : Extended Base Pointer esp : Extended Stack Pointer eip : Extended Instruction Pointer Generally the size of those registers is 32bit (=4 bytes). They can hold data from 0-FFFFFFFF (unsigned). In the beginning most registers had certain main functions which the name imply, like ECX = Counter or so, but in these days you can - nearly - use whichever register you like for a counter or stuff (only the selfdefined ones, there are counter-functions which need to be used with ECX). The functions of EAX, EBX, ECX, EDX, ESI and EDI will be explained when I explain certain functions that use those registers. So, there are EBP, ESP, EIP left. EBP: EBP has mostly to do with stack and stackframes. Nothing you really need to worry about, when you start. ;) ESP: ESP points to the stack of a current process. The stack is the place where data can be stored for later use (for more information, see the explanation of the push/pop instructions) EIP: EIP always points to the next instruction that is to be executed. There's one more thing you have to know about registers: Although they are all 32bit large, only some parts of them (16bit or even 8bit can be addressed directly). The names for those operations are: 32bit register 16bit register 8bit register EAX AX AH/AL EBX BX BH/BL ECX CX CH/CL EDX DX DH/DL ESI SI - EDI DI - EBP BP - ESP SP - EIP IP - A register looks generally this way: |------------------------------- EAX: 32bit (=1 DWORD) -----------------------------| |----------- AX: 16bit (=1 WORD) ---------| |- AH:8bit (=1 BYTE)-|- AL:8bit (=1 BYTE)-| |-----------------------------------------|--------------------|--------------------| |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX| |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX| |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXXXXXX| |-----------------------------------------|--------------------|--------------------| So, EAX is the name of the 32bit register, AX is the name of the "Low Word" (16bit) of EAX and AH/AL are the names of the "High Word" and the "Low Word" of EAX (8bit). --------------------------------------------------------------------------------------------- The flags: Flags are single bits which indicate current states of something. The flag register on modern 32bit CPUs is 32bit large -> There are 32 different flags, but don't worry. You will only need 3 of them for cracking. The Z-Flag, the O-Flag and the C-Flag. For cracking you need to know those flags to know if a jump is executed or not. The Z-Flag: The Z-Flag (zero flag) is the most useful flag for cracking. It is used in about 95% of all cases. It can be set (status: 1) or cleared (status: 0) by several opcodes when the last instruction that was performed has 0 as result. You might wonder why "cmp" (more on this later) could set the zero flag, because it compares something and has how can the result of a comparison be 0. The answer on this comes later ;) The O-Flag: The O-Flag (overflow flag) is used in about 4% of all cracking attempts. It is set (status: 1) when the last operation changed the highest bit of the register that gets the result of an operation. For example: EAX holds the value 7FFFFFFF. If you use an operation now, which increases EAX by 1 the O-Flag would be set, because the operation changed the highest bit of EAX (which is not set in 7FFFFFFF, but set in 80000000 - use calc.exe to convert hexadecimal values to binary values). Another need for the O-Flag to be set, is that the value of the destination register is neither 0 before the instruction nor after it. The C-Flag: The C-Flag (Carry flag) is used in about 1% of all cracking attempts. It is set, if you add a value to a register, so that it gets bigger than FFFFFFFF or if you subtract a value, so that the register value gets smaller than 0. --------------------------------------------------------------------------------------------- OK, now we can go to the instructions (sorted in alphabetical order): Most instructions have two operators (like "add eax, ebx"), but some have one ("not eax") or even three ("imul eax, edx, 64"). When you have an instruction that says something with "DWORD PTR [XXX]" then the DWORD (4 byte) value at memory offset [XXX] is meant. Note, that the bytes are saved in reverse order in the memory (WinTel CPUs use the so called "Little Endian" format). The same is for "WORD PTR [XXX]" (2 byte) and "BYTE PTR [XXX]" (1 byte). Most instructions with 2 operators can be used in the following ways (example: add) add eax, ebx ;; Register, Register add eax, 123 ;; Register, Value add eax, dword ptr [404000] ;; Register, Dword Pointer [value] add eax, dword ptr [eax] ;; Register, Dword Pointer [register] add eax, dword ptr [eax+00404000] ;; Register, Dword Pointer [register+value] add dword ptr [404000], eax ;; Dword Pointer [value], Register add dword ptr [404000], 123 ;; Dword Pointer [value], Value add dword ptr [eax], eax ;; Dword Pointer [register], Register add dword ptr [eax], 123 ;; Dword Pointer [register], Value add dword ptr [eax+404000], eax ;; Dword Pointer [register+value], Register add dword ptr [eax+404000], 123 ;; Dword Pointer [register+value], value Please note, that all values in asm mmnemonics (instructions) are *always* hexadecimal. --------------------------------------------------------------------------------------------- ADD (Addition) Syntax: ADD destination, source The ADD instruction adds a value to a register or a memory address. It can be used in these ways: These instruction can set the Z-Flag, the O-Flag and the C-Flag (and some others, which are not needed for cracking). --------------------------------------------------------------------------------------------- AND (Logical And) Syntax: AND destination, source The AND instruction used logical AND on two values. This instruction *will* clear the O-Flag and the C-Flag and can set the Z-Flag. To understand AND better, consider those two binary values: 1001010110 0101001101 If you AND them, the result is 0001000100 When two 1 stand below each other, the result is of this bit is 1, if not: The result is 0. You can use calc.exe to calculate AND easily. If you want further information, read chapter 3 (Boolean Algebra) in "Art of Assembly" (protools.cjb.net should have it) --------------------------------------------------------------------------------------------- CALL (Call) Syntax: CALL something The instruction CALL pushes the RVA (Relative Virtual Address) of the instruction that follows the CALL to the stack and calls a sub program/procedure. Call can be used in the following ways: call 404000 ;; MOST COMMON: CALL ADDRESS call EAX ;; CALL REGISTER - IF EAX WOULD BE 404000 IT WOULD BE SAME AS THE ONE ABOVE call DWORD PTR [EAX] ;; CALLS THE ADDRESS THAT IS STORED AT [EAX] call DWORD PTR [EAX+5] ;; CALLS THE ADDRESS THAT IS STORED AT [EAX+5] --------------------------------------------------------------------------------------------- CDQ (Convert DWord (4Byte) to QWord (8 Byte)) Syntax: CQD CDQ is an instruction that always confuses newbies when it appears first time. It is mostly used in front of divisions and does nothing else then setting all bytes of EDX to the value of the highest bit of EAX. (That is: if EAX <80000000, then EDX will be 00000000; if EAX >= 80000000, EDX will be FFFFFFFF). --------------------------------------------------------------------------------------------- CMP (Compare) Syntax: CMP dest, source The cmp instruction compares two things and can set the C/O/Z flags if the result fits. cmp eax, ebx ;; compares eax and ebx and sets z-flag if they are equal cmp eax, [404000] ;; compares eax with the dword at 404000 cmp [404000], eax ;; compares eax with the dword at 404000 --------------------------------------------------------------------------------------------- DEC (Decrement) Syntax: DEC something dec is used to decrease a value (that is: value=value-1) dec can be used in the following ways: dec eax ;; decrease eax dec [eax] ;; decrease the dword that is stored at [eax] dec [401000] ;; decrease the dword that is stored at [401000] dec [eax+401000] ;; decrease the dword that is stored at [eax+401000] The dec instruction can set the Z/O flags if the result fits. --------------------------------------------------------------------------------------------- DIV (Division) Syntax: DIV divisor DIV is used to divide EAX through divisor (unsigned division). The dividend is always EAX, the result is stored in EAX, the modulo-value in EDX. An example: mov eax, 64 ; EAX = 64h = 100 mov ecx, 9 ; ECX = 9 div ecx ; DIVIDE EAX THROUGH ECX After the division EAX = 100/9 = 0B and ECX = 100 MOD 9 = 1 The div instruction can set the C/O/Z flags if the result fits. --------------------------------------------------------------------------------------------- IDIV (Integer Division) Syntax: IDIV divisor The IDIV works in the same way as DIV, but IDIV is a signed division. The idiv instruction can set the C/O/Z flags if the result fits. --------------------------------------------------------------------------------------------- IMUL (Integer Multiplication) Syntax: IMUL value IMUL dest, value, value IMUL dest, value IMUL multiplies either EAX with value (IMUL value) or it multiplies two values and puts them into a destination register (IMUL dest, value, value) or it multiplies a register with a value (IMUL dest, value). If the multiplication result is too big to fit into the destination register, the O/C flags are set. The Z flag can be set, too. --------------------------------------------------------------------------------------------- INC (Increment) Syntax: INC register INC is the opposite of the DEC instruction; it increases values by 1. INC can set the Z/O flags. --------------------------------------------------------------------------------------------- JUMPS: Those are the most important jumps and the condition that needs to be met, so that they'll be executed (Important jumps are marked with * and very important with **): *JA - Jump if (unsigned) above - CF=0 and ZF=0 JAE - Jump if (unsigned) above or equal - CF=0 *JB - Jump if (unsigned) below - CF=1 JBE - Jump if (unsigned) below or equal - CF=1 or ZF=1 JC - Jump if carry flag set - CF=1 JCXZ - Jump if CX is 0 - CX=0 **JE - Jump if equal - ZF=1 JECXZ - Jump if ECX is 0 - ECX=0 *JG - Jump if (signed) greater - ZF=0 and SF=OF (SF = Sign Flag) *JGE - Jump if (signed) greater or equal - SF=OF *JL - Jump if (signed) less - SF != OF (!= is not) *JLE - Jump if (signed) less or equal - ZF=1 and SF != OF **JMP - Jump - Jumps always JNA - Jump if (unsigned) not above - CF=1 or ZF=1 JNAE - Jump if (unsigned) not above or equal - CF=1 JNB - Jump if (unsigned) not below - CF=0 JNBE - Jump if (unsigned) not below or equal - CF=0 and ZF=0 JNC - Jump if carry flag not set - CF=0 **JNE - Jump if not equal - ZF=0 JNG - Jump if (signed) not greater - ZF=1 or SF!=OF JNGE - Jump if (signed) not greater or equal - SF!=OF JNL - Jump if (signed) not less - SF=OF JNLE - Jump if (signed) not less or equal - ZF=0 and SF=OF JNO - Jump if overflow flag not set - OF=0 JNP - Jump if parity flag not set - PF=0 JNS - Jump if sign flag not set - SF=0 JNZ - Jump if not zero - ZF=0 JO - Jump if overflow flag is set - OF=1 JP - Jump if parity flag set - PF=1 JPE - Jump if parity is equal - PF=1 JPO - Jump if parity is odd - PF=0 JS - Jump if sign flag is set - SF=1 JZ - Jump if zero - ZF=1 --------------------------------------------------------------------------------------------- LEA (Load Effective Offset) Syntax: LEA dest, src LEA can be treated the same way as the MOV instruction. It ain't used too much for it's original function, but more for quick multiplications like this: lea eax, dword ptr [4*ecx+ebx] which gives eax the value of 4*ecx+ebx --------------------------------------------------------------------------------------------- MOV (Move) Syntax: MOV dest, src This is a very command and easy to understand instruction. MOV copies the value from src to dest and src stays what it was before. There are some variants of MOV: MOVS/MOVSB/MOVSW/MOVSD: Those variants copy the byte/word/dword ESI points to to the space EDI points to. MOVSX: MOVSX expands Byte or Word operands to Word or Dword size and keeps the sign of the value. MOVZX: MOVZX expands Byte or Word operands to Word or Dword size and fills the rest of the space with 0. --------------------------------------------------------------------------------------------- MUL (Multiplication) Syntax: MUL value This instruction is the same as IMUL, except that it multiplies unsigned. It can set the O/Z/F flags. --------------------------------------------------------------------------------------------- NOP (No Operation) Syntax: NOP This instruction does absolutely nothing (That's the reason why it is used for patches so often ;) --------------------------------------------------------------------------------------------- OR (Logical Inclusive Or) Syntax: OR dest, src The OR instruction connects two values using the logical inclusive or. This instruction *will* clear the O-Flag and the C-Flag and can set the Z-Flag. To understand OR better, consider those two binary values: 1001010110 0101001101 If you OR them, the result is 1101011111 Only when there are two 0 on top of each other, the resulting bit is 0. Else the resulting bit is 1. You can use calc.exe to calculate OR easily. If you want further information, read chapter 3 (Boolean Algebra) in "Art of Assembly" (protools.cjb.net should have it) --------------------------------------------------------------------------------------------- POP Syntax: POP dest POP loads the value of byte/word/dworp ptr [esp] and puts it into dest. Additionaly it increases the stack by the size of the value that was popped of the stack, so that the next POP would get the next value. --------------------------------------------------------------------------------------------- PUSH Syntax: PUSH operand PUSH is the opposite of POP. It stores a value on the stack and decreases it by the size of the operand that was pushed, so that ESP points to the value that was PUSHed. --------------------------------------------------------------------------------------------- RET (Return) Syntax: RET RET digit RET does nothing but return from a part of code that was reached using a CALL instruction. RET digit only cleans the stack a bit, before it returns. --------------------------------------------------------------------------------------------- SUB (Subtraction) Syntax: SUB dest, src SUB is the opposite of the ADD command. It subtracts the value of src from the value of dest and stores the result in dest. SUB can set the Z/O/C flags. --------------------------------------------------------------------------------------------- TEST Syntax: TEST operand1, operand2 This instruction is in 99% of all cases used for "TEST EAX, EAX". It performs a Logical And (AND Command) but does not save the values. It only sets the Z-Flag, when EAX is 0 or clears it, when EAX is not 0. The O/C flags are always cleared. --------------------------------------------------------------------------------------------- XOR Syntax: XOR dest, src The XOR instruction connects two values using logical exclusive or (OR uses inclusive or, you remember). This instruction *will* clear the O-Flag and the C-Flag and can set the Z-Flag. To understand XOR better, consider those two binary values: 1001010110 0101001101 If you OR them, the result is 1100011011 When two bits on top of each other are equal, the resulting bit is 0. Else the resulting bit is 1. You can use calc.exe to calculate XOR easily. If you want further information, read chapter 3 (Boolean Algebra) in "Art of Assembly" (protools.cjb.net should have it) The most often seen use of XOR is "XOR EAX, EAX". This will set EAX to 0, because when you XOR a value with itself, the result is always 0. I hope you understand why, else write down a value on paper and try ;) --------------------------------------------------------------------------------------------- Now I will present you a short (useless) code example that demonstrates the use of all instructions I presented. mov eax, 100 ;; EAX = 100h = 256 mov ebx, 200 ;; EBX = 200h = 512 mov ecx, 9 ;; ECX = 9h = 9 xor edx, edx ;; EDX = 0h = 0 add eax, ebx ;; ADD EBX TO EAX; NOW EAX IS 300h sub eax, 300 ;; SUBTRACT 300 FROM EAX; EAX IS 0 NOW AND THE INSTRUCTION SETS THE Z-FLAG je SOMEWHERE ;; IF Z-FLAG SET (IN THIS CASE) JUMP TO SOMEWHERE (=MEMORY ADDRESS) ... SOMEWHERE: ;; HERE WE GO ON or eax, 1234 ;; USES LOGICAL OR ON EAX (=0); THE RESULT IS 1234h and eax, 567 ;; USES LOGICAL AND ON EAX (=1234); THE RESULT IS 24h test eax, eax ;; EAX AIN'T 0, SO THE Z-FLAG IS NOT SET je SOMEWHERE ;; NO JUMP HERE - Z-FLAG IS NOT SET call SOMETHING ;; THIS CALLS A SUBPROGRAM (SEE BELOW) cmp eax, 5000h ;; COMPARES EAX WITH 4623h - EAX IS NOT THIS VALUE, SO THE Z-FLAG IS NOT SET jne SOMEWHERE2 ;; IF Z-FLAG NOT SET (IN OUR CASE): JUMP .... GO ON DOING STUFF SOMETHING: inc eax ;; INCREMENTS EAX (EAX IS 23h NOW) imul ebx ;; EAX = EAX*EBX = 23h*200h = 4600h ; EDX IS SET TO 0 push eax ;; SAVES THE VALUE OF EAX ON THE STACK dec ebx ;; EBX IS 1FFh NOW cdq ;; AIN'T NEEDED HERE, BECAUSE EDX IS ALREADY 0, BUT YOU BETTER ALWAYS USE IT FOR IDIV idiv ebx ;; EAX IS EAX / EBX = 23h ; EDX IS 23h pop ebx ;; NOW THE LAST VALUE THAT WAS PUSHED ON THE STACK IS READ AND PUT IN EBX: 4600h xor eax, ebx ;; XORs 23h AND 4600h ; RESULT IS 4623h ret ;; RETURNS FROM SUB PROGRAM --------------------------------------------------------------------------------------------- So, that's all. If you want to learn more about assembly, you should visit win32asm.cjb.net and protools.cjb.net (To get "Art of Assembly"). III. BTW Greetings go to: +Sandman, Acid Burn, alpine, BlackB, Blind Angel, Borna Janes, Carpathia, CrazyKnight, DEATH, DEZM, dimwitz, DnNuke, duelist, Eternal Bliss, Fravia+, Iczelion, Jordan, KnowledgeIsPower, Knotty, Kwazy Webbit, Lucifer48, MisterE, Neural Noise, noos, Prof.X, R!SC, rubor, Shadow, SiG, tC, The AntiXryst, The Hobgoblin, TORN@DO, ultraschall, viny, Volatility, wAj WarezPup, _y and all the guys I forget and I'll add next time.