Page cover

Getting Started

August 8th, 2025

Overview

Assembly Functions

General Purpose Registers

This can be thought of as the foundation for tasks and operations. They are held in the CPU's super-fast storage locations. When you want to compute an arithmetic operation, do a simple for loop, or grow gray hairs, the GPRs are in play.

All the Assembly Registers relating to the GPRs

Segments

As such, with every programming language, there must be a way to perform actions. The GP instructions perform basic movement, arithmetic, logic, program flow, and string operations that are used to write application and system software. Although we won't mention every data instruction, we will cover the important ones for Assembly programming.

Moving data between the memory and other regions of the CPU can be thought of as this:

When looking at a process, there is one task that must happen: segmentation. Think of your process as a pie; what segmentation does is cut that pie into varying sizes depending on a person's desired slice.

This is the same case for Segmentation, the segment registers are constantly used for numerous important tasks, from moving memory and data to fetching instructions. Each segment that they point to can be a different size, similar to how your friends may have different sizes for their pie.

Definition for all the Segment Registries (except for GS and FS)

Registers

Assembly uses Registers which are small and fast storage components within a CPU, they can be used for performing multiple tasks while maintaining efficiency. The types of registers include; General-Purpose Registers, Flag Registers, Segment Registers, Pointer Registers and Index Registers.

Registers can be paired with other instructions such as mov, add, or . The leading "E" indicates that it is a 32-bit register, meanwhile, a leading "R" would indicate a 64-bit register

General-Purpose Registers

General-Purpose Registers can be used to storage data, addresses or calculate.

Name
Use Case

EAX

Accumulator Register used for arithmetic purpose

EBX

Base Register used for addressing

ECX

Count Register used for loop operations

EDX

Data Register used in conjunction with EAX for certain operations

Registers also consist of their lower and higher bit counter parts. 32-bit registers use the "E" letter for extended registers, while 64-bit registers use the "R" letter for a full Register. These both stem from the 16-bit register which does not have a leading letter, consisting of AX, BX, CX, and DX . Lastly, there are 8-bit registers which are taken from the lower and higher half of a 16-bit register.

64-bit
16-bit
8-bit

RAX

AH, AL

RBX

BH, BL

RCX

CH, CL

RDX

DH, DL

Index Registers

Index Registers consist of their 32 and 16-bit counterparts, which aid in addition and subtraction (sometimes), but are mainly used for indexed addressing.

Name
Use Case

RSI (64-bit) ESI (32-bit) SI (16-bit)

source index for string operations

RDI (64-bit) EDI (32-bit) Di (16-bit)

destination index for string operations

In terms of string operations, these are not to be confused with generic strings (such as print statements). These registers input and output from a buffer index and are generally used with the following functions:

  1. MOVSB - Move a byte from ESI to EDI

  2. MOVSW - Move a word (16-bit)

  3. MOVSD - Move a double word (32-bit)

  4. MOVSQ - Move a quad word (64-bit)

  5. STOS - Store from AL/AX/EAX/RAX to EDI/RDI

  6. LDOS - Load from EDI/RDI to AL/AX/EAX/RAX

An example of this would be the code listed below, the char buffer[400] allows a maximum of 400 bytes, which is correctly matched with the reading process of (0, buffer, 400); anything past this would result in a buffer overflow. The buffer pointer would be the EDI, as it will be used to point to the destination; an ESI is nowhere to be found due to .

int buffer()
{
  char buffer[400];
  int input;
  input = read(0, buffer, 400);
  printf("\n[+] user supplied: %d bytes!",input);
  printf("\n[+] buffer content --> %s!", buffer);
  return 0;
}

Pointer Registers

Pointer Registers are designed to hold a memory address from another location, handle function calls, point to data in memory, and assist in memory operations. They are commonly used to control micro-controllers by accessing the . Similar to all other registers, they consist of 64, 32, and 16-bit versions, respectively.

Name
Type
Use Case

Instruction Pointer

RIP(64) EIP(32) IP(16)

stores the of the next instruction to be executed

Stack Pointer

RSP(64) ESP(32) SP(16)

provides the offset value within the program stack

Base Pointer

RBP(64) EBP(32) BP(16)

helps in referencing the parameter variables passed to a

Data Movement

X86 Assembly has an immense amount of data transfer instructions; someone like you and me may just lose their heads trying to understand everything. However, fret not, for we will only be covering the necessary Assembly instructions in accordance with our Malware Analysis, learning more is always a good thing, but for our sake, keeping our sanity is the first of our problems!

mov - move data from GPRs, move data between memory and GP/Segment Registers, or move immediately to GPRs

push - push onto a stack

pop - pop (remove) off the stack

xchg - exchange

bswap - byte swap

dst - destination (where a value is stored or written)

src - source (data being read or manipulated)

Debugging Example

#include <windows.h>
#include <stdio.h>

int main() {


	puts("---/*Creating Open Handle*/---");

	STARTUPINFO info = { sizeof(info) };
	PROCESS_INFORMATION processinfo;
	LPCWSTR path = L"C:\\Windows\\system32\\notepad.exe";

	printf("Creating Process! \n");
	CreateProcess(path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &info, &processinfo);

	DWORD PID = processinfo.dwProcessId;
	printf("[i] Current Process ID: %ld", PID);

	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

	if (hProcess == NULL) {
		printf("[-] Could not open process, error: %ld", GetLastError());
		return EXIT_FAILURE;
	}

	printf("\n[0x%p] Got a handle to the process!\n", hProcess);
	CloseHandle(hProcess);
	CloseHandle(processinfo.hProcess);
	CloseHandle(processinfo.hThread);
	puts("[>] Press Enter Key to Exit");
	(void)getchar();
	return EXIT_SUCCESS;
}

The C program above opens a handle from a specific , which then prints out the handle to the process using the OpenProcess Function.

Looking at the information provided by x64DBG, we can see the OpenHandle program

References

Last updated