Context

If you have decided to read my OSED notes, there are a few things you should know.

I started keeping this diary on the first day of my training and aimed to write regularly for 90 days. However, despite working daily, I couldn’t find the time to update it every day. Therefore, I’ve decided to share the notes I’ve taken instead of the complete diary entries.

Please note that there will be no private information about Offsec’s resources included in these notes. If I mention any applications, they will be examples that can be accessed publicly.

As a final note, as I mentioned in the “Whoami” section, these notes were not written for you. So, do not expect any useful or educational information from them. You may encounter some irrelevant content, cheatsheets, or theoretical explanations. These notes are primarily for my own reference to track my progress and review when needed. If you are looking for a better resource, I recommend you take this education and create your own comprehensive resource.

Intro - Assembly

As a start, it is useful to read the contents below.

Assembly Language – Wikipedia
Assembly Language Tutorial – SkullSecurity Wiki

Here are some notes I took.


EAX: Arithmetical and LogicalInstructions - Used for storing operands and result data
EBX: Base Pointer for Memory Addresses - Pointer to data
ECX: Loop, shift, rotation counter - Loop operations
EDX: I/O Port Addressing, Multiplication, Division - I/O Pointer
ESI: Pointer of data and source in string copy operations - Data Pointer Registers for memory operations
EDI: Pointer of data and destination in string copy operations - Data Pointer Registers for memory operations

ESP: Stack Pointer
EBP: Base Pointer
EIP: The Instruction Pointer

WinDbg Commands

Display Commands

Windows Symbol Path: srv*c:\symbols"https://msdl.microsoft.com/download/symbols"
Reload Symbols (Force): .relaod /f 
Unassamble from memory:  u <code>  (ex: u kernel32!GetCurrentThread)
                    
db: Display bytes format  
dw: Display WORDs (two bytes) format
dd: Display DWORDs (four bytes) format
dq: Display QWORDs (eight bytes) format
dW: Display WORDs (two bytes) format with string
dc: Display DWORDs (four bytes) format with string
dd poi(address):  Display data referenced from memory address
dt <name of structure>: Display Data Structures  (ex: dt ntdll!_TEB)
dt -r <name of structure> @$<name>: Recursively display nested structures (ex: dt -r ntdll!_TEB @$teb) 

e\* <address>: Editing to Memory address (ex: ed esp 41414141) 
s -<data-type option> <start address> L?<end address> <value>: (ex: s -d 0 L?80000000 41414141)
Data-Type Options:
-d :  DWORDs
-a :  ASCII string
-u :  Unicode string

r: Intercepting CPU Registers
r <address> <new value>: Display and edit to address (ex: r ecx=41414141)

Breakpoints

bp :  Breakpoint 
bl :  List of break points 
be :  Enable breakpoint
bd :  Disable breakpoint
bc * :  Delete all breakpoints

A hardware breakpoint consists of three commands.

ba <access type> <size in bytes> <address>  (ex: ba e 1 kernel32!WriteFile)
Access Types: e (execute), r (read), w (write)

Stepping throught the code commands:

p: Executes a single instruction 
t: Executes a single instruction or source line and optionally displays the resulting values of all registers and flags
pt: The pt command executes the program until a return instruction is reached.
ph: Command executes the program until any kind of branching instruction is reached.

Some of the contents I have read.

dt (Display Type) - Microsoft
Pseudo-Register Syntax - Microsoft
Common WinDbg Commands - windbg.info

Badchars Payload

    b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
    b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
    b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
    b"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
    b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
    b"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
    b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
    b"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
    b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
    b"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
    b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
    b"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
    b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
    b"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
    b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
    b"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

SEH Overflow

Some of the content I have read.

A Modern Exploration of Windows Memory Corruption Exploits - Part 1: Stack Overflows - Forres-Orr
Win32 Thread Information Block - Wikipedia
Except-Handler3 - Microsoft
Structured Exception Handling - Microsoft

Shellcode

How to Syscall Works

The user space program makes a syscall to request a specific service from the operating system. The processor transfers control to the corresponding syscall handler, which then calls the appropriate syscall routine to perform the requested operation using privileged resources. Once the syscall routine completes, the control is passed back to the syscall handler, which, in turn, returns the result to the user space program. This mechanism allows user space programs to interact with the operating system in a controlled and secure manner, while keeping the critical system resources protected and managed by the kernel.

Systemcall registery distributions on x86 systems are as follows.

EAX = System Call number
EBX = 1st argument
ECX = 2nd argument
EDX = 3rd argument
ESI = 4th argument
EDI = 5th argument

For example, when we want to syscall the Write function, something like the following occurs.

ssize_t write (EAX - system call number) (int fd (EBX - 1st argument), const void *buf (ECX - 2nd argument), size_t count (EDX - 3rd argument));

Example assembly code that calls the Write function, and prints “Hello World!”

; Hello World in xi386 assembly for Linux

global _start

section .text
_start:

    ;print hello world on the screen

    mov edx, mlen
    mov ecx, message
    mov ebx, 1  
    mov eax, 4  ; write syscall
    int 0x80

    mov ebx, 0
    mov eax, 1  ;exit syscall
    int 0x80

section .data
    message: db "Hello, World!"
    mlen equ $-message

Data Types

There are several data types that can be used in assembly language. The most commonly used data types are BYTE, WORD, DWORD, QWORD, TBYTE, DQWORD, and XMMWORD. The BYTE data type is an 8-bit data type, WORD is a 16-bit data type, DWORD is a 32-bit data type, and QWORD is a 64-bit data type.

db -> single byte - 8 bits
dw -> double word - 16 bits
dd -> double word - 32 bits
dq -> quad word - 64 bits
dt -> double quad word bytes - 80 bits
b 0x55                     ;just the byte 0x55
db 0x55, 0x56, 0x57         ; three bytes in succession
db 'a', 0x55,               ; character constants are OK
db 'hello', 13, 10, '$'     ; so are string constants
dw 0x1234                   ; 0x34 0x12
dw 'a'                      ; 0x61 0x00 (it's just a number)
dw 'ab'                     ; 0x61 0x62 (character constant)
dw 'abc'                    ; 0x61 0x62 0x63 0x00 (string)
dd 0x12345678               ; 0x78 0x56 0x34 0x12
dd 1.234567e20              ; floating point constant
dq 1.234567e20              ; double-precision float
dt 1.234567e20              ; extended-precision float

Data Range


; Natural Range
byte (8-bit)(signed)   : 0 < x < 255
word (16-bit)         : 0 < x < 65.535
dword (32-bit)        : 0 < x < 4.294.967.215

; Integer Range
byte (8-bit)(unsigned) : -128 < x < 127
word (16-bit)          : -32.768 < x < 32.767
dword (32-bit)        : -2.147.483.684 < x < 2.147.483.647 

Data Moving

mov eax, msg    ; Transfer the memory location into eax. Also transfer the content of register.
mov eax, [msg]  ; Transfer the value into eax
lea eax, [msg]  ; Loading the address of "msg" into the "eax" register, not the content of "msg" 

EFLAGS Registers

Zero Flag (ZF)      : Set if the result of the operation is zero.
Overflow Flag (OF)  : Set if there's an overflow in signed operations.
Carry Flag (CF)     : Set if there's a carry out in the operation.
Sign Flag (SF)      : Reflects the sign of the result.

Arithmetic Instructions


ADD: This instruction adds the values of two operands. For instance, in assembly language, an instruction like ADD AX, BX would add the values in the AX and BX registers.
SUB: This is the subtraction instruction. SUB AX, BX would subtract the value in BX from AX.
MUL: Multiplication. MUL BX typically multiplies the accumulator (like AX) with BX.
DIV: Division. DIV BX usually divides the accumulator by BX.
INC: Increment. Increases the value of an operand by one. For example, INC AX would increase the value in the AX register by one.
DEC: Decrement. Decreases the value of an operand by one.
NEG: Negate. Changes the sign of the value in a register or memory location.

Logical Instructions

AND: This instruction performs a bitwise AND operation between two operands. If a particular bit is set (1) in both operands, then the corresponding result bit is set. Otherwise, it's cleared (0).
Example: AND AX, BX would perform a bitwise AND between the values in registers AX and BX and store the result in AX.

OR: Performs a bitwise OR operation. If a particular bit is set in either operand (or both), the corresponding result bit is set.
Example: OR AX, BX

XOR: Bitwise exclusive OR (XOR) operation. If a particular bit is set in one operand but not both, the corresponding result bit is set.
Example: XOR AX, BX

NOT: Bitwise NOT operation. It inverts each bit of the operand.
Example: NOT AX would invert all the bits in AX.

SHL/SAL (Shift Left): Shifts the bits of the operand to the left by a specified number of positions, filling the vacated positions with zeros. This effectively multiplies the number by powers of two.
Example: SHL AX, 1 shifts the bits in AX one position to the left.

SHR (Shift Right): Shifts the bits of the operand to the right by a specified number of positions, filling the vacated positions with zeros. This effectively divides unsigned numbers by powers of two.
Example: SHR AX, 1

SAR (Arithmetic Shift Right): Similar to SHR, but it keeps the sign bit (usually the leftmost bit in two's complement representation) the same as it was, which is helpful for signed numbers.

ROL (Rotate Left) and ROR (Rotate Right): Similar to shifts, but the bits that are shifted out at one end are shifted back in at the other end.

These logical operations often affect the flags in a processor’s status or flags register, especially the Zero Flag (ZF), Parity Flag (PF), and Sign Flag (SF). For instance:

Zero Flag (ZF)   : Set if the result of the operation is zero.
Parity Flag (PF) : Set if the number of set bits in the result is even.
Sign Flag (SF)   : Reflects the sign of the result (0 for positive, 1 for negative in two's complement representation).

Conditional Instructions

CMP (Compare): This instruction compares two operands by essentially subtracting one from the other without storing the result. It's used to set the relevant flags, especially Zero Flag (ZF), Carry Flag (CF), and Sign Flag (SF), based on the result. These flags can then be checked by subsequent conditional jump instructions.
JE/JZ (Jump if Equal / Jump if Zero): Jumps to the specified address if the Zero Flag (ZF) is set. Typically used after a CMP instruction to check for equality.
JNE/JNZ (Jump if Not Equal / Jump if Not Zero): Jumps if the Zero Flag is not set.
JG/JNLE (Jump if Greater / Jump if Not Less or Equal): Jumps if a value is greater than another in signed comparison.
JGE/JNL (Jump if Greater or Equal / Jump if Not Less): Jumps if a value is greater than or equal to another in signed comparison.
JL/JNGE (Jump if Less / Jump if Not Greater or Equal): Jumps if a value is less than another in signed comparison.
JLE/JNG (Jump if Less or Equal / Jump if Not Greater): Jumps if a value is less than or equal to another in signed comparison.
JB/JNAE/JC (Jump if Below / Jump if Not Above or Equal / Jump if Carry): Used for unsigned comparisons to jump if one value is less (below) than another.
JBE/JNA (Jump if Below or Equal / Jump if Not Above): For unsigned comparisons.
JA/JNBE (Jump if Above / Jump if Not Below or Equal): Used for unsigned comparisons to jump if one value is greater (above) than another.
JO (Jump if Overflow): Jumps if the Overflow Flag (OF) is set.
JNO (Jump if No Overflow): Jumps if the Overflow Flag is not set.
JS (Jump if Sign): Jumps if the Sign Flag (SF) is set (i.e., the result is negative in two's complement representation).
JNS (Jump if No Sign): Jumps if the Sign Flag is not set. 

String Instructions

SI (or ESI in 32-bit, RSI in 64-bit): Source Index, used to point to the source string.
DI (or EDI in 32-bit, RDI in 64-bit): Destination Index, used to point to the destination string.
CX (or ECX in 32-bit, RCX in 64-bit): Counter register, often used to specify the number of characters or bytes to process.

Here’s a breakdown of some common string instructions:

MOVS (Move String): Copies data from the source string to the destination string. Depending on the operand size, it can be MOVSB (move byte), MOVSW (move word), or MOVSD (move doubleword). After each operation, SI and DI are incremented or decremented based on the direction flag (DF).
LODS (Load String): Loads data from the source string into the accumulator register (AL, AX, or EAX). Like MOVS, there are variations such as LODSB, LODSW, and LODSD. The SI register is updated after the operation.
STOS (Store String): Stores data from the accumulator to the destination string. Variations include STOSB, STOSW, and STOSD. The DI register is updated after each operation.
SCAS (Scan String): Compares the accumulator with the destination string's element. After the comparison, the DI register is updated. Variations include SCASB, SCASW, and SCASD.
CMPS (Compare Strings): Compares an element from the source string with an element from the destination string. Both SI and DI are updated after the operation. Variations include CMPSB, CMPSW, and CMPSD.
REP (Repeat): This is a prefix used with other string instructions to repeat them based on the value in the CX (or ECX/RCX) register. For example, REP MOVSB will repeatedly move bytes from source to destination, decrementing CX with each iteration, until CX reaches zero.
REPE/REPZ (Repeat Equal/Repeat Zero) and REPNE/REPNZ (Repeat Not Equal/Repeat Not Zero): These prefixes work like REP but also take into account the Zero Flag (ZF). They're often combined with SCAS or CMPS to search or compare strings.

The direction in which the SI and DI registers are updated (incremented or decremented) depends on the Direction Flag (DF) in the flags register. If DF is clear (0), SI and DI are incremented after each operation. If DF is set (1), they are decremented. The instructions CLD and STD are used to clear and set the DF, respectively.

Content To Read

Smashing The Stack For Fun And Profit - Umich.edu
Compiler Warning (Level 3) - Microsoft
/SAFESEH (Image has Safe Exception Handlers) - Microsoft
Data Execution Prevention - Microsoft
/DYNAMICBASE (Use address space layout randomization) - Microsoft
Preventing the Exploitation of SEH Overwrites with SEHOP - Microsoft
Bypassing Stack Cookie, SafeSeh, SEHOP, HW DEP and ASLR - Corelan
DEP (Data Execution Prevention) Explanation by Example - 0xdabbad00
Masking Malicious Memory Artifacts - Phantom DLL Hollowing - Forrest-Orr