🐳
Swayam's Blog
LinkedinGithub
  • 🫚root@Swayam's Blog
  • 🕺About Me
  • 🛠️Projects
    • CurveLock
    • ShadowChain
  • 🐞Malware Analysis
    • Basic Malware Analysis
      • LAB Network Setup
      • Basic Static Analysis
      • Basic Dynamic Analysis
      • Advanced Dynamic Analysis
      • Advanced Static Analysis
      • Identifying Anti analysis techniques
      • Binary Patching
      • Shellcode Analysis
      • Malware.unknown.exe.Malz
      • Challenge-Sillyputty
      • Bind_shell RAT Analysis
      • Malicious Powershell Script
      • Malicious HTA(HTML Applications)
      • Phishing Excel Embedded Malware
      • Reversing Csharp And DotNET Framework
      • YARA rules
      • Automating Malware Analysis
    • MASM 64 Bit Assembly
      • Hello World Of Assembly Language
      • Computer Data Representation and Operations
      • Memory Access And Organization
      • Constants, Variables And Data Types
      • Procedures
      • Arithmetic
      • Low Level Control Structures
  • 👨‍💻Malware/Exploit Development
    • Driver Development
      • Driver 101
      • Kernel Calbacks
      • Process Protection
      • Process Token Privilege
  • 📖Notes And Cheatsheets
    • OSCP / Application Security
      • OS stuff
        • Footprinting
        • Nmap
        • Shells
        • Metasploit
        • Windows Buffer Overflow
        • Windows
        • Windows Privilege Escalation
        • Linux Commands
        • Linux Privilege Escalation
        • Password Cracking
        • Pivoting And Tunneling
        • Macos
      • General Introduction
        • Basic Tools
        • Basic Networking
      • WebApps
        • Attacking Common Applications
        • Attacking Common Services
        • Broken Authentication
        • Burp Proxy
        • Common Apps
        • Command Injection
        • ffuf Fuzzing
        • File Inclusion
        • File Transfer
        • File Upload
        • Javascript Deobfuscation
        • Password Attacks
        • SQLi
        • Web attacks
        • Web Information Gathering
        • Wordpress
        • Brute Forcing
        • HTTP Curl
      • Active Directory
    • Wireless Attacks
    • Red Teaming
    • BloodHound
    • Pentesting
    • ADCS
  • 🚩CTFs
    • Flare-On
      • Flare-On 1 (2014)
        • Challenge 1
Powered by GitBook
On this page
  • Statement Labels
  • Trampolines
  • Conditional Move Instructions
  • Implementing Common Control Structures in MASM
  • Switch Statement
  • State Machines and Indirect Jumps
  • Loops
  1. Malware Analysis
  2. MASM 64 Bit Assembly

Low Level Control Structures

Chapter 7

Statement Labels

  • labels stand in as symbolic names for addresses.

  • You can do three things with (code) labels: transfer control to a label via a (conditional or unconditional) jump instruction, call a label via the call instruction, and take the address of a label. Taking the address of a label is useful when you want to indirectly transfer control to that address at a later point in your program.

stmtLbl:
 .
 .
 .
        mov rcx, offset stmtLbl2
 .
 .
 .
        lea rax, stmtLbl
 .
 .
 .
stmtLbl2:

Using Local Symbols in Procedures

  • Statement labels you define within a proc/endp procedure are local to that procedure

        option  casemap:none

        
            .code

hasLocalLbl proc

localStmLbl:
            ret
hasLocalLbl endp


; Here is the "asmMain" function.

        
asmMain     proc

asmLocal:   jmp	      asmLocal	      ;This is okay
	    jmp	      localStmtLbl    ;Undefined in asmMain
asmMain     endp
            end
  • If you really want to access a statement (or any other) label outside a procedure, you can use the option directive to turn off local scope within a section of your program

option noscoped
option scoped
;; example

        option  casemap:none

        
            .code

hasLocalLbl proc

localStmLbl:
            option noscoped
notLocal:
            option scoped
isLocal:
            ret
hasLocalLbl endp


; Here is the "asmMain" function.

        
asmMain     proc

            lea     rcx, localStmtLbl  ;Generates an error
            lea     rcx, notLocal      ;Assembles fine
            lea     rcx, isLocal       ;Generates an error
asmMain     endp
            end

Initializing Arrays with Label Addresses

  • MASM also allows you to initialize quad-word variables with the addresses of statement labels.

        option  casemap:none

            .data
lblsInProc  qword   globalLbl1, globalLbl2  ;From procWLabels
        
            .code


;procWLabels-
; Just a procedure containing private (lexically scoped)
; and global symbols. This really isn't an executable
; procedure.
 
procWLabels proc
privateLbl:
            nop     ;"No operation" just to consume space
            option  noscoped
globalLbl1: jmp     globalLbl2
globalLbl2: nop
            option  scoped
privateLbl2:
            ret
dataInCode  qword   privateLbl, globalLbl1
            qword   globalLbl2, privateLbl2
procWLabels endp
            
            end

Trampolines

  • In the rare case you need to branch to a location beyond the range of the 6-byte jcc instructions you can use a trampoline such as the on below :

        jncc skipJmp ; Opposite jump of the one you want to use
        jmp destPtr ; JMP PC-relative is also limited to ±2GB
destPtr qword destLbl ; so code must use indirect jump
skipJmp:
  • The opposite conditional branch transfers control to the normal fall though point in the code. If the condition is true, control transfers to a memory indirect jump that jumps to the original target location via a 64-bit pointer.

Conditional Move Instructions

  • Because branches can be somewhat expensive to execute, the x86-64 CPUs support a set of conditional move instructions, cmovcc.

;; cmovcc forms

cmovcc reg16, reg16
cmovcc reg16, mem16
cmovcc reg32, reg32
cmovcc reg32, mem32
cmovcc reg64, reg64
cmovcc reg64, mem64
  • In addition, a set of conditional floating-point move instructions (fcmovcc) will move data between ST0 and one of the other FPU registers on the FPU stack. Sadly, these instructions aren’t all that useful in modern programs.

Implementing Common Control Structures in MASM

; if ((x > y) && (z < t)) or (a != b) c = d;
; Implemented as:

; if (a != b) then goto DoIf:
                  mov eax, a
                  cmp eax, b
                  jne DoIf

; if not (x > y) then goto EndOfIf:
                  mov eax, x
                  cmp eax, y
                  jng EndOfIf

; if not (z < t) then goto EndOfIf:
                  mov eax, z
                  cmp eax, t
                  jnl EndOfIf

; THEN block:
DoIf:
                  mov eax, d
                  mov c, eax
; End of IF statement.
EndOfIf:

Complex if Statements Using Complete Boolean Evaluation

; if(((x < y) && (z > t)) || (a != b))
; Stmt1
                 mov eax, x
                 cmp eax, y
                 setl bl         ; Store x < y in BL
                 mov eax, z
                 cmp eax, t
                 setg bh         ; Store z > t in BH
                 and bl, bh      ; Put (x < y) && (z > t) into BL
                 mov eax, a
                 cmp eax, b
                 setne bh        ; Store a != b into BH
                 or bl, bh       ; Put (x < y) && (z > t) || (a != b) into BL
                 je SkipStmt1    ; Branch if result is false
           
           Code for Stmt1 goes here
SkipStmt1:

Short-Circuit Boolean Evaluation

; if((x < y) && (z > t)) then ...

        mov eax, x
        cmp eax, y
        jnl TestFails
        mov eax, z
        cmp eax, t
        jng TestFails
        
    Code for THEN clause of IF statement
    
TestFails:


; if(ch < 'A' || ch > 'Z')
;         then printf("Not an uppercase char");
; endif;

        cmp ch, 'A'
        jb ItsNotUC
        cmp ch, 'Z'
        jna ItWasUC
        
ItsNotUC:
        Code to process ch if it's not an uppercase character
        
ItWasUC:


; if(((x < y) && (z > t)) || (a != b)) Stmt1 ;

        mov eax, a
        cmp eax, b
        jne DoStmt1
        mov eax, x
        cmp eax, y
        jnl SkipStmt1
        mov eax, z
        cmp eax, t
        jng SkipStmt1

DoStmt1:
        Code for Stmt1 goes here
SkipStmt1:

Switch Statement

if/else Implementation of switch

; if/then/else/endif form:

         mov eax, i
         test eax, eax ; Check for 0
         jnz Not0
         
         Code to print "i = 0"
         jmp EndCase
         
Not0:
         cmp eax, 1
         jne Not1
         
         Code to print "i = 1"
         jmp EndCase
         
Not1:
         cmp eax, 2
         jne EndCase;
         
         Code to print "i = 2"
EndCase: 

Indirect Jump switch Implementation

; Indirect Jump Version.

        mov eax, i
        lea rcx, JmpTbl
        jmp qword ptr [rcx][rax * 8]
JmpTbl qword Stmt0, Stmt1, Stmt2

Stmt0:
        Code to print "i = 0"
        jmp EndCase;

Stmt1:
        Code to print "i = 1"
        jmp EndCase;

Stmt2:
        Code to print "i = 2"
EndCase: 

Noncontiguous Jump Table Entries and Range Limiting

; SWITCH statement specifying cases 1, 2, 4, and 8
; with a DEFAULT clause:

        mov eax, i
        cmp eax, 1
        jb DefaultCase
        cmp eax, 8 ; Verify that i is in the range
        ja DefaultCase ; 1 to 8 before the indirect jmp
        lea rcx, JmpTbl
        jmp qword ptr [rcx][rax * 8 – 1 * 8] ; 1 * 8 compensates for zero index

JmpTbl  qword Stmt1, Stmt2, DefaultCase, Stmt4
        qword DefaultCase, DefaultCase, DefaultCase, Stmt8

Stmt1:
        Code to print "i = 1"
        jmp EndCase

Stmt2:
        Code to print "i = 2"
        jmp EndCase

Stmt4:
        Code to print "i = 4"
        jmp EndCase

Stmt8:
        Code to print "i = 8"
        jmp EndCase

DefaultCase:
        Code to print "i does not equal 1, 2, 4, or 8"

EndCase: 

Sparse Jump Tables

  • The current implementation of the switch statement has a problem. If the case values contain nonconsecutive entries that are widely spaced, the jump table could become exceedingly large.

; Assume expression has been calculated into EAX.
         cmp eax, 100
         jb t
         ja try1000_10000
        
         Code to handle case 100 goes here
         jmp AllDone

try1_10:
         cmp eax,1
         je case1
         cmp eax, 10
         jne defaultCase
         Code to handle case 10 goes here
         jmp AllDone

case1:
         Code to handle case 1 goes here
          jmp AllDone

try1000_10000:
          cmp eax, 1000
          je case1000
          cmp eax, 10000
          jne defaultCase
          Code to handle case 10000 goes here
          jmp AllDone

case1000:
          Code to handle case 1000 goes here
          jmp AllDone

defaultCase:
           Code to handle defaultCase goes here

AllDone:

State Machines and Indirect Jumps

  • Another control structure commonly found in assembly language programs is the state machine. A state machine uses a state variable to control program flow.

  • So what is a state machine? In basic terms, it is a piece of code that keeps track of its execution history by entering and leaving certain states.

  • Suppose you have a procedure and want to perform one operation the first time you call it, a different operation the second time you call it, yet something else the third time you call it, and then something new again on the fourth call. After the fourth call, it repeats these four operations in order.

; A simple state machine example

        option  casemap:none

nl          =       10

            .const
fmtStr0     byte    "Calling StateMachine, "
            byte    "state=%d, EAX=5, ECX=6", nl, 0
            
fmtStr0b    byte    "Calling StateMachine, "
            byte    "state=%d, EAX=1, ECX=2", nl, 0
            
fmtStrx     byte    "Back from StateMachine, "
            byte    "state=%d, EAX=%d", nl, 0
            
fmtStr1     byte    "Calling StateMachine, "
            byte    "state=%d, EAX=50, ECX=60", nl, 0
            
fmtStr2     byte    "Calling StateMachine, "
            byte    "state=%d, EAX=10, ECX=20", nl, 0
            
fmtStr3     byte    "Calling StateMachine, "
            byte    "state=%d, EAX=50, ECX=5", nl, 0
            
            
            
            .data
state       byte    0


            .code
            externdef printf:proc
            
StateMachine proc
             cmp    state, 0
             jne    TryState1
             
; State 0: Add ecx to eax and switch to State 1:

             add    eax, ecx
             inc    state   ; State 0 becomes state 1
             jmp    exit

TryState1:
             cmp    state, 1
             jne    TryState2

; State 1: Subtract ecx from eax and switch to state 2:

             sub    eax, ecx
             inc    state           ; State 1 becomes state 2.
             jmp    exit


TryState2:   cmp    state, 2
             jne    MustBeState3

; If this is State 2, multiply ecx by eax and switch to state 3:

             imul   eax, ecx
             inc    state           ; State 2 becomes state 3.
             jmp    exit

; If it isn't one of the above states, we must be in State 3,
; so divide eax by ecx and switch back to State 0.

MustBeState3:
             push   rdx          ; Preserve this 'cause it gets whacked by div.
             xor    edx, edx     ; Zero extend eax into edx.
             div    ecx
             pop    rdx          ; Restore edx's value preserved above.
             mov    state, 0     ; Reset the state back to 0.
             
exit:        ret

StateMachine endp
            
            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 48         ;Shadow storage
            
            mov     state, 0        ;Just to be safe
            
; Demonstrate state 0:

            lea     rcx, fmtStr0
            movzx   rdx, state
            call    printf
            
            mov     eax, 5
            mov     ecx, 6
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     r8, rax
            movzx   edx, state
            call    printf
            
; Demonstrate state 1:

            lea     rcx, fmtStr1
            movzx   rdx, state
            call    printf
            
            mov     eax, 50
            mov     ecx, 60
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     r8, rax
            movzx   edx, state
            call    printf
            
; Demonstrate state 2:

            lea     rcx, fmtStr2
            movzx   rdx, state
            call    printf
            
            mov     eax, 10
            mov     ecx, 20
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     r8, rax
            movzx   edx, state
            call    printf
            
; Demonstrate state 3:

            lea     rcx, fmtStr3
            movzx   rdx, state
            call    printf
            
            mov     eax, 50
            mov     ecx, 5
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     r8, rax
            movzx   edx, state
            call    printf
            
; Demonstrate back in state 0:

            lea     rcx, fmtStr0b
            movzx   rdx, state
            call    printf
            
            mov     eax, 1
            mov     ecx, 2
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     r8, rax
            movzx   edx, state
            call    printf
            
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end
  • Technically, this procedure is not the state machine. Instead, the variable state and the cmp/jne instructions constitute the state machine. The procedure is little more than a switch statement implemented via the if/then/elseif construct.

  • It’s common to use an indirect jump to implement a state machine in assembly language. Rather than having a state variable that contains a value like 0, 1, 2, or 3, we could load the state variable with the address of the code to execute upon entry into the procedure.

; An indirect jump state machine example

        option  casemap:none

nl          =       10

            .const
fmtStr0     byte    "Calling StateMachine, "
            byte    "state=0, EAX=5, ECX=6", nl, 0
            
fmtStr0b    byte    "Calling StateMachine, "
            byte    "state=0, EAX=1, ECX=2", nl, 0
            
fmtStrx     byte    "Back from StateMachine, "
            byte    "EAX=%d", nl, 0
            
fmtStr1     byte    "Calling StateMachine, "
            byte    "state=1, EAX=50, ECX=60", nl, 0
            
fmtStr2     byte    "Calling StateMachine, "
            byte    "state=2, EAX=10, ECX=20", nl, 0
            
fmtStr3     byte    "Calling StateMachine, "
            byte    "state=3, EAX=50, ECX=5", nl, 0
            
            
             .data
state        qword  state0
           

            .code
            externdef printf:proc

; StateMachine version 2.0- using an indirect jump.

             option noscoped        ;statex labels must be global
StateMachine proc
             
             jmp    state
             
             
; State 0: Add ecx to eax and switch to State 1:

state0:      add    eax, ecx
             lea    rcx, state1
             mov    state, rcx
             ret

; State 1: Subtract ecx from eax and switch to state 2:

state1:      sub    eax, ecx
             lea    rcx, state2
             mov    state, rcx
             ret

; If this is State 2, multiply ecx by eax and switch to state 3:

state2:      imul   eax, ecx
             lea    rcx, state3
             mov    state, rcx
             ret

state3:      push   rdx          ; Preserve this 'cause it gets whacked by div.
             xor    edx, edx     ; Zero extend eax into edx.
             div    ecx
             pop    rdx          ; Restore edx's value preserved above.
             lea    rcx, state0
             mov    state, rcx
             ret

StateMachine endp
             option scoped
            
            
; Here is the "asmMain" function.

        
            public  asmMain
asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 48         ;Shadow storage
            
            lea     rcx, state0
            mov     state, rcx        ;Just to be safe
            
; Demonstrate state 0:

            lea     rcx, fmtStr0
            call    printf
            
            mov     eax, 5
            mov     ecx, 6
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     rdx, rax
            call    printf
            
; Demonstrate state 1:

            lea     rcx, fmtStr1
            call    printf
            
            mov     eax, 50
            mov     ecx, 60
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     rdx, rax
            call    printf
            
; Demonstrate state 2:

            lea     rcx, fmtStr2
            call    printf
            
            mov     eax, 10
            mov     ecx, 20
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     rdx, rax
            call    printf
            
; Demonstrate state 3:

            lea     rcx, fmtStr3
            call    printf
            
            mov     eax, 50
            mov     ecx, 5
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     rdx, rax
            call    printf
            
; Demonstrate back in state 0:

            lea     rcx, fmtStr0b
            call    printf
            
            mov     eax, 1
            mov     ecx, 2
            call    StateMachine
            
            lea     rcx, fmtStrx
            mov     rdx, rax
            call    printf
            
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end

Loops

While loops

        mov i, 0

WhileLp:
        cmp i, 100
        jnl WhileDone
        inc i
        jmp WhileLp;

WhileDone:

Do-While loops

do_while_loop:
    ; Body of the loop
    mov eax, counter
    call PrintNumber         ; Assume PrintNumber prints EAX

    ; Increment counter
    inc counter

    ; Check condition: while (counter < 5)
    mov eax, counter
    cmp eax, 5
    jl do_while_loop         ; Jump if less than 5

    ret
main ENDP

; Dummy print procedure for illustration
PrintNumber PROC
    ; Implement your print logic here
    ret
PrintNumber ENDP

forever/endfor Loops

foreverLabel:
        call getchar         ; Assume it returns char in AL
        cmp al, '.'
        je ForIsDone
        mov cl, al           ; Pass char read from getchar to putchar
        call putcchar        ; Assume this prints the char in CL
        jmp foreverLabel

ForIsDone:

for Loops

         xor rbx, rbx ; Use RBX to hold loop index

WhileLp: 
         cmp ebx, 7
         jnl EndWhileLp
         
         lea rcx, fmtStr ; fmtStr = "Array Element = %d", nl, 0
         lea rdx, S
         mov rdx, [rdx][rbx * 4] ; Assume SomeArray is 4-byte ints
         call printf

         inc rbx
         jmp WhileLp;
         
EndWhileLp:

The break and continue Statements

  • To convert a break statement to pure assembly language, just emit a goto/jmp instruction that transfers control to the first statement following the end of the loop to exit. You can do this by placing a label after the loop body and jumping to that label.

// Breaking out of a FOR(;;) loop:
for (;;) {
    // Statements before break
    // break;
    goto BreakFromForever;

    // Statements after break (unreachable)
}
BreakFromForever:

// Breaking out of a FOR loop:
for (initStmt; expr; incStmt) {
    // Statements before break
    // break;
    goto BrkFromFor;

    // Statements after break (unreachable)
}
BrkFromFor:

// Breaking out of a WHILE loop:
while (expr) {
    // Statements before break
    // break;
    goto BrkFromWhile;

    // Statements after break (unreachable)
}
BrkFromWhile:

// Breaking out of a REPEAT/UNTIL loop (similar to DO/WHILE):
do {
    // Statements before break
    // break;
    goto BrkFromRpt;

    // Statements after break (unreachable)
} while (!expr);
BrkFromRpt:
  • In pure assembly language, convert the appropriate control structures to assembly and replace the goto with a jmp instruction.

; for(;;)/continue/endfor
; Conversion of FOREVER loop with continue
; to pure assembly:

    for(;;)
    {
        Stmts
        continue;
        Stmts
    }

; Converted code:

foreverLbl:
        Stmts
        ; continue;
        jmp foreverLbl
        Stmts
        jmp foreverLbl
        
______________________________________________________________________

; while/continue/endwhile
; Conversion of WHILE loop with continue
; into pure assembly:

    while(expr)
    {
        Stmts
        continue;
        Stmts
    }

; Converted code:

whlLabel:
        Code to evaluate expr
        jcc EndOfWhile     ; Skip loop on expr failure
        Stmts
        ; continue;
        jmp whlLabel       ; Jump to start of loop on continue
        Stmts
        jmp whlLabel       ; Repeat the code
EndOfWhile:
______________________________________________________________________

; for/continue/endfor
; Conversion for a FOR loop with continue
; into pure assembly:

    for(initStmt; expr; incStmt)
    {
        Stmts
        continue;
        Stmts
    }

; Converted code:

        initStmt
ForLpLbl:
        Code to evaluate expr
        jcc EndOfFor       ; Branch if expression fails
        Stmts
        ; continue;
        jmp ContFor        ; Branch to incStmt on continue
        Stmts
ContFor:
        incStmt
        jmp ForLpLbl
EndOfFor:
______________________________________________________________________

;repeat/continue/until
    repeat
        Stmts
        continue;
        Stmts
    until(expr);

    do
    {
        Stmts
        continue;
        Stmts
    } while (!expr);

; Converted code:

RptLpLbl:
        Stmts
        ; continue;
        jmp ContRpt        ; Continue branches to termination test
        Stmts
ContRpt:
        Code to test expr
        jcc RptLpLbl       ; Jumps if expression evaluates false

Registers in loops

  • Registers are more efficient than memory locations and are perfect for manipulating data. But due to their limited availability, they must used alongside the stack. Whenever a register is to be accessed, it's value must be preserved and should be restored after we are done with it.

        mov cx, 8

loop1:
        push rcx
        mov cx, 4

loop2:
        Stmts
        dec cx
        jnz loop2;
        pop rcx
        dec cx
        jnz loop1

;;  or

        mov dx,8

loop1:
        mov cx, 4

loop2:
        Stmts
        dec cx
        jnz loop2
        dec dx
        jnz loop1
  • Register corruption is one of the primary sources of bugs in loops in assembly language programs, so always keep an eye out for this problem.

Loop Performance Improvements

  1. Moving the Termination Condition to the End of a Loop.

  2. Executing the Loop Backward

  3. Using Loop-Invariant Computations - A loop-invariant computation is a calculation that appears within a loop that always yields the same result. You needn’t do such computations inside the loop. You can compute them outside the loop and reference the value of the computations inside the loop.

  4. Using Induction Variables - you can reduce the execution time of the body of the loop by using induction variables. An induction variable is one whose value depends entirely on the value of another variable.

PreviousArithmeticNextDriver Development

Last updated 1 day ago

🐞
cmovcc Instructions That Test Flags
cmovcc Instructions That Test Flags
cmovcc Instructions for Unsigned Comparisons
cmovcc Instructions for Signed Comparisons