Binary Exploitation

x86 Assembly Implementations

x86 assembly language implementations covering common patterns, instruction set reference, calling conventions, and translating C to assembly.

Contents

x86 Assembly Implementations

Assumptions: 32-bit x86, stdcall convention, null-terminated C-strings. No prologue/epilogue shown (assume wrapped in proper function). Minimal error handling.


String Length Functions

strlen

Prototype: size_t strlen(const char* str);
Returns: Length excluding null terminator

mov edi, [ebp+8]    ; str
xor eax, eax        ; AL=0 (search for null)
or ecx, -1          ; max count
repne scasb         ; scan until null found
not ecx             ; ECX = scanned bytes (len+1)
dec ecx             ; exclude null terminator
mov eax, ecx        ; return length

strnlen

Prototype: size_t strnlen(const char* str, size_t maxlen);
Returns: Length up to maxlen, excluding null

mov edi, [ebp+8]    ; str
mov ecx, [ebp+0Ch]  ; maxlen
xor eax, eax        ; AL=0
jecxz done          ; if maxlen=0, return 0
repne scasb         ; scan for null or maxlen reached
jne no_null         ; maxlen reached without null
inc ecx             ; null found, adjust
no_null:
mov eax, [ebp+0Ch]  ; maxlen
sub eax, ecx        ; actual length
done:

String Search Functions

strchr

Prototype: char* strchr(const char* str, int ch);
Returns: Pointer to first occurrence of ch, or NULL

mov edi, [ebp+8]    ; str
mov al, [ebp+0Ch]   ; ch (byte)
or ecx, -1          ; max count
repne scasb         ; scan for AL
jne not_found       ; no match
lea eax, [edi-1]    ; back up to match position
jmp done
not_found:
xor eax, eax        ; return NULL
done:

strrchr

Prototype: char* strrchr(const char* str, int ch);
Returns: Pointer to last occurrence of ch, or NULL

mov edi, [ebp+8]    ; str
mov dl, [ebp+0Ch]   ; ch to find
xor eax, eax        ; last found = NULL
scan_loop:
mov cl, [edi]       ; current char
test cl, cl         ; check for null
jz done             ; end of string
cmp cl, dl          ; compare with ch
jne next
mov eax, edi        ; update last found
next:
inc edi
jmp scan_loop
done:

strstr

Prototype: char* strstr(const char* haystack, const char* needle);
Returns: Pointer to first occurrence of substring, or NULL

mov edi, [ebp+8]    ; haystack
mov esi, [ebp+0Ch]  ; needle
mov al, [esi]       ; first char of needle
test al, al         ; empty needle?
jz found_at_start   ; return haystack
outer_loop:
mov cl, [edi]       ; current haystack char
test cl, cl         ; end of haystack?
jz not_found
cmp cl, al          ; first char match?
jne next_pos
; Check full substring
push edi
push esi
inc edi
inc esi
inner_loop:
mov dl, [esi]       ; needle char
test dl, dl         ; end of needle?
jz match_found
cmp dl, [edi]       ; compare
jne no_match
inc edi
inc esi
jmp inner_loop
match_found:
pop esi
pop eax             ; return start position
jmp done
no_match:
pop esi
pop edi
next_pos:
inc edi
jmp outer_loop
not_found:
xor eax, eax        ; return NULL
jmp done
found_at_start:
mov eax, edi        ; return haystack
done:

Memory Operations

memcpy

Prototype: void* memcpy(void* dst, const void* src, size_t n);
Returns: dst pointer

mov edi, [ebp+8]    ; dst
mov esi, [ebp+0Ch]  ; src
mov ecx, [ebp+10h]  ; n (byte count)
rep movsb           ; copy ECX bytes
mov eax, [ebp+8]    ; return dst

memset

Prototype: void* memset(void* dst, int ch, size_t n);
Returns: dst pointer

mov edi, [ebp+8]    ; dst
mov al, [ebp+0Ch]   ; ch (byte value)
mov ecx, [ebp+10h]  ; n (byte count)
rep stosb           ; fill ECX bytes with AL
mov eax, [ebp+8]    ; return dst

memcmp

Prototype: int memcmp(const void* s1, const void* s2, size_t n);
Returns: 0 if equal, <0 if s1<s2, >0 if s1>s2

mov edi, [ebp+8]    ; s1
mov esi, [ebp+0Ch]  ; s2
mov ecx, [ebp+10h]  ; n
jecxz equal         ; n=0, consider equal
repe cmpsb          ; compare until mismatch
je equal            ; all bytes matched
mov al, [edi-1]     ; last byte from s1
sub al, [esi-1]     ; difference (s1-s2)
movsx eax, al       ; sign extend
jmp done
equal:
xor eax, eax        ; return 0
done:

String Comparison

strcmp

Prototype: int strcmp(const char* s1, const char* s2);
Returns: 0 if equal, <0 if s1<s2, >0 if s1>s2

mov edi, [ebp+8]    ; s1
mov esi, [ebp+0Ch]  ; s2
cmp_loop:
mov al, [edi]       ; char from s1
mov dl, [esi]       ; char from s2
cmp al, dl          ; compare
jne not_equal       ; difference found
test al, al         ; both null?
jz equal            ; yes, strings equal
inc edi
inc esi
jmp cmp_loop
not_equal:
movzx eax, al       ; zero-extend s1 char
movzx edx, dl       ; zero-extend s2 char
sub eax, edx        ; return difference
jmp done
equal:
xor eax, eax        ; return 0
done:

strncmp

Prototype: int strncmp(const char* s1, const char* s2, size_t n);
Returns: 0 if equal up to n chars, <0 if s1<s2, >0 if s1>s2

mov edi, [ebp+8]    ; s1
mov esi, [ebp+0Ch]  ; s2
mov ecx, [ebp+10h]  ; n
jecxz equal         ; n=0, equal
cmp_loop:
mov al, [edi]       ; char from s1
mov dl, [esi]       ; char from s2
cmp al, dl          ; compare
jne not_equal
test al, al         ; null terminator?
jz equal
inc edi
inc esi
loop cmp_loop       ; decrement ECX, loop if not zero
equal:
xor eax, eax        ; return 0
jmp done
not_equal:
movzx eax, al
movzx edx, dl
sub eax, edx        ; return difference
done:

String Copy Functions

strcpy

Prototype: char* strcpy(char* dst, const char* src);
Returns: dst pointer

mov edi, [ebp+8]    ; dst
mov esi, [ebp+0Ch]  ; src
copy_loop:
lodsb               ; load byte from [esi] to AL, inc esi
stosb               ; store AL to [edi], inc edi
test al, al         ; null terminator?
jnz copy_loop       ; continue if not
mov eax, [ebp+8]    ; return dst

strncpy

Prototype: char* strncpy(char* dst, const char* src, size_t n);
Returns: dst pointer (may not be null-terminated if src >= n chars)

mov edi, [ebp+8]    ; dst
mov esi, [ebp+0Ch]  ; src
mov ecx, [ebp+10h]  ; n
jecxz done          ; if n=0, nothing to copy
copy_loop:
lodsb               ; load from src
stosb               ; store to dst
test al, al         ; was it null?
loopnz copy_loop    ; continue if not null and ecx>0
; Pad with nulls if needed
jz pad_nulls
jmp done
pad_nulls:
xor al, al          ; AL=0
rep stosb           ; fill rest with nulls
done:
mov eax, [ebp+8]    ; return dst

String Concatenation

strcat

Prototype: char* strcat(char* dst, const char* src);
Returns: dst pointer

mov edi, [ebp+8]    ; dst
mov esi, [ebp+0Ch]  ; src
; Find end of dst
xor eax, eax        ; search for null
or ecx, -1          ; max count
repne scasb         ; find null in dst
dec edi             ; back to null position
; Copy src to end
cat_loop:
lodsb               ; load from src
stosb               ; store to dst
test al, al         ; null terminator?
jnz cat_loop
mov eax, [ebp+8]    ; return dst

strncat

Prototype: char* strncat(char* dst, const char* src, size_t n);
Returns: dst pointer (always null-terminated)

mov edi, [ebp+8]    ; dst
mov esi, [ebp+0Ch]  ; src
mov edx, [ebp+10h]  ; n
; Find end of dst
xor eax, eax
or ecx, -1
repne scasb
dec edi             ; back to null position
; Copy up to n chars
test edx, edx       ; n=0?
jz add_null
cat_loop:
lodsb               ; load from src
test al, al         ; src ended?
jz add_null
stosb               ; store to dst
dec edx             ; decrement n
jnz cat_loop        ; continue if n>0
add_null:
xor al, al          ; ensure null terminator
stosb
mov eax, [ebp+8]    ; return dst

String Modification

strset

Prototype: char* strset(char* str, int ch);
Returns: str pointer (sets all chars to ch, preserving null)

mov edi, [ebp+8]    ; str
mov edx, edi        ; save dst pointer
xor eax, eax        ; AL=0
or ecx, -1          ; max count
repne scasb         ; find null terminator
add ecx, 2
neg ecx             ; ECX = string length
mov al, [ebp+0Ch]   ; ch (fill character)
mov edi, edx        ; reset to start
rep stosb           ; fill with ch
mov eax, edx        ; return str

strupr

Prototype: char* strupr(char* str);
Returns: str pointer (converts to uppercase)

mov edi, [ebp+8]    ; str
mov esi, edi        ; save for return
upper_loop:
mov al, [edi]       ; load char
test al, al         ; null terminator?
jz done
cmp al, 'a'         ; less than 'a'?
jb next_char
cmp al, 'z'         ; greater than 'z'?
ja next_char
sub al, 32          ; convert to uppercase
mov [edi], al       ; store back
next_char:
inc edi
jmp upper_loop
done:
mov eax, esi        ; return str

strlwr

Prototype: char* strlwr(char* str);
Returns: str pointer (converts to lowercase)

mov edi, [ebp+8]    ; str
mov esi, edi        ; save for return
lower_loop:
mov al, [edi]       ; load char
test al, al         ; null terminator?
jz done
cmp al, 'A'         ; less than 'A'?
jb next_char
cmp al, 'Z'         ; greater than 'Z'?
ja next_char
add al, 32          ; convert to lowercase
mov [edi], al       ; store back
next_char:
inc edi
jmp lower_loop
done:
mov eax, esi        ; return str

Notes

  • String instructions (REP prefix) use ECX as counter
  • Direction flag (DF) assumed clear (0) for forward processing
  • SCASB: scan string (compare AL with [EDI]), increment/decrement EDI
  • STOSB: store string (AL to [EDI]), increment/decrement EDI
  • LODSB: load string ([ESI] to AL), increment/decrement ESI
  • MOVSB: move string ([ESI] to [EDI]), increment/decrement both
  • CMPSB: compare strings ([ESI] with [EDI]), increment/decrement both