CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/byakugan/jutsu.cpp
Views: 11766
1
#include <stdio.h>
2
#include <winsock2.h>
3
#include <ws2tcpip.h>
4
#include "byakugan.h"
5
#include "jutsu.h"
6
#include "msfpattern.h"
7
#include "stdwindbg.h"
8
9
struct requestQueue jutsuRequests;
10
struct trackedBuf *trackedBufList = NULL;
11
struct trackedVal *trackedValList = NULL;
12
13
ULONG64 disassemblyBuffer;
14
HANDLE processHandle = 0;
15
16
SOCKET ListenSocket = INVALID_SOCKET,
17
ClientSocket = INVALID_SOCKET;
18
19
20
//IDebugClient msfClient;
21
22
23
char *regs[] = {
24
"eax",
25
"ebx",
26
"ecx",
27
"edx",
28
"esp",
29
"ebp",
30
"eip",
31
NULL
32
};
33
34
void helpJutsu(void) {
35
return;
36
}
37
38
void memDiffJutsu(char *inputType, DWORD size, char *input, ULONG64 address) {
39
DWORD i, j, valResult, readSize, numBadChars = 0;
40
BOOL upperFlag, lowerFlag, nullFlag;
41
char *pureBuf = NULL, findValExpression[64] = {'\x00'};
42
char lineExpected[16], lineActual[16];
43
44
struct trackedBuf *curr = trackedBufList;
45
struct corruption *badChars;
46
47
// Valid inputs: ASCII, hex, file, buf
48
if (!_stricmp(inputType, "ASCII")) {
49
pureBuf = input;
50
} else if (!_stricmp(inputType, "hex")) {
51
if (size != parseHexInput(input, size, pureBuf)) {
52
dprintf("[J] Failed to parse %d bytes from hex input.\n", size);
53
return;
54
}
55
} else if (!_stricmp(inputType, "file")) {
56
readSize = readFileIntoBuf(input, size, &pureBuf, 0);
57
if ((size && size != readSize) || readSize == 0) {
58
dprintf("[J] Failed to read %d bytes from %s.\n", size, input);
59
return;
60
}
61
size = (size ? size : readSize);
62
} else if (!_stricmp(inputType, "buf")) {
63
// Grab the buf by name from the trackedBufList
64
65
while (curr != NULL) {
66
if(!_stricmp(input, curr->bufName)) {
67
pureBuf = curr->bufPatt;
68
break;
69
}
70
curr = curr->next;
71
}
72
if (pureBuf == NULL) {
73
dprintf("[J] Unable to find buffer: %s\n", input);
74
return;
75
}
76
} else {
77
dprintf("[J] The valid input types are buf, hex, and file.\n");
78
return;
79
}
80
81
upperFlag = lowerFlag = nullFlag = FALSE;
82
badChars = (struct corruption *) malloc(size * sizeof (struct corruption));
83
84
dprintf("\t\t\tACTUAL\t\t\t\t\t\t\t\tEXPECTED\n");
85
for (i = 0; i < size; i++) {
86
// Get byte at the important memory location
87
StringCchPrintf(findValExpression, sizeof(findValExpression),
88
"poi(0x%08x)", address + i);
89
valResult = (GetExpression(findValExpression) & 0xFF);
90
91
lineExpected[i%16] = pureBuf[i];
92
lineActual[i%16] = valResult;
93
94
if (pureBuf[i] != valResult) {
95
badChars[numBadChars].value = pureBuf[i];
96
badChars[numBadChars].offset = i;
97
badChars[numBadChars].seenAgain = FALSE;
98
badChars[numBadChars].seenBefore = FALSE;
99
for (j = 0; j < numBadChars; j++) {
100
if (badChars[j].value == badChars[numBadChars].value) {
101
badChars[numBadChars].seenBefore = TRUE;
102
}
103
}
104
numBadChars++;
105
} else {
106
for (j = 0; j < numBadChars; j++)
107
if (valResult == badChars[j].value)
108
badChars[j].seenAgain = TRUE;
109
}
110
111
112
if (i % 16 == 15 || i == size-1) {
113
// Print the actual characters with differences in bold
114
for (j = 0; j != i % 16 + 1; j++) {
115
// Diff the two locations
116
if (lineActual[j] != lineExpected[j]) {
117
// Store badchars, and bad offsets
118
// Print this character in bold!
119
StringCchPrintf(findValExpression, sizeof(findValExpression),
120
".printf /D \"<b><red>%02x</red></b> \"", lineActual[j]);
121
g_ExtControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, findValExpression,
122
DEBUG_EXECUTE_NOT_LOGGED);
123
124
} else {
125
dprintf("%02x ", lineActual[j]);
126
}
127
128
// Take note of upper / lower / null exclusions
129
}
130
if (i == size-1)
131
for (j = 0; j < 15 - i % 16; j+=2)
132
dprintf("\t");
133
dprintf("\t");
134
135
// Now print the Expected characters
136
for (j = 0; j != i % 16 + 1; j++) {
137
dprintf("%02x ", lineExpected[j]);
138
}
139
dprintf("\n");
140
}
141
}
142
143
// Display bad chars
144
i = 0;
145
if (numBadChars) {
146
dprintf("\n[J] Bytes replaced: ");
147
while (i < numBadChars) {
148
if (!badChars[i].seenAgain && !badChars[i].seenBefore)
149
dprintf("0x%02x ", badChars[i].value);
150
i++;
151
}
152
i = 0;
153
dprintf("\n[J] Offset corruption occurs at: ");
154
while (i < numBadChars) {
155
if (badChars[i].seenAgain)
156
dprintf("%02x ", badChars[i].offset);
157
i++;
158
}
159
dprintf("\n");
160
}
161
162
// Unless pureBuf came from a tracked buffer, free the memory
163
if (_stricmp(inputType, "buf"))
164
free(pureBuf);
165
free(badChars);
166
}
167
168
void listTrackedVals() {
169
struct trackedVal *newTrackedVal;
170
171
if (trackedValList == NULL) {
172
dprintf("[J] Currently tracking no primitive values.\n");
173
return;
174
}
175
176
dprintf("[J] Currently tracking:\n");
177
178
newTrackedVal = trackedValList;
179
while (newTrackedVal != NULL) {
180
dprintf("\tName: %s\t\tSize: %d\tCandidates: %d\n",
181
newTrackedVal->valName, newTrackedVal->valSize, newTrackedVal->candidates);
182
newTrackedVal = newTrackedVal->next;
183
}
184
}
185
186
void listTrackedValByName(char *name) {
187
struct trackedVal *newTrackedVal;
188
struct valInstance *curr;
189
190
newTrackedVal = trackedValList;
191
if (newTrackedVal == NULL) goto nada;
192
193
while (newTrackedVal != NULL) {
194
if (!_stricmp(newTrackedVal->valName, name))
195
break;
196
newTrackedVal = newTrackedVal->next;
197
}
198
199
if (newTrackedVal) {
200
201
curr = newTrackedVal->instances;
202
203
if (curr != NULL)
204
dprintf("[J] Currently tracking %d candidates for %s:\n",
205
newTrackedVal->candidates, newTrackedVal->valName);
206
else
207
goto nada;
208
209
while (curr != NULL) {
210
dprintf("\tAddress: 0x%08x\n", curr->address);
211
curr = curr->next;
212
}
213
return;
214
}
215
nada:
216
dprintf("[J] No candidates are being tracked for %s.\n", name);
217
}
218
219
void trackValJutsu(char *name, DWORD size, DWORD value) {
220
struct trackedVal *newTrackedVal, *parent = NULL;
221
struct valInstance *last, *curr;
222
char findValExpression[18] = {'\x00'};
223
DWORD valResult, andExpression;
224
225
switch(size) {
226
case 1: andExpression = 0xFF; break;
227
case 2: andExpression = 0xFFFF; break;
228
case 4: andExpression = 0xFFFFFFFF; break;
229
default:
230
dprintf("[J] Valid primitive sizes are 1, 2, and 4.\n");
231
return;
232
}
233
234
newTrackedVal = trackedValList;
235
while (newTrackedVal != NULL) {
236
if (!_stricmp(newTrackedVal->valName, name))
237
break;
238
newTrackedVal = newTrackedVal->next;
239
}
240
241
// Search the list for the new value, purge old addresses
242
if (newTrackedVal) {
243
dprintf("[J] Narrowing down candidate list for %s from %d candidates.\n", name, newTrackedVal->candidates);
244
curr = newTrackedVal->instances;
245
last = NULL;
246
247
while (curr != NULL) {
248
StringCchPrintf(findValExpression, sizeof(findValExpression), "poi(0x%08x)", curr->address);
249
valResult = (GetExpression(findValExpression) & andExpression);
250
if (value != valResult) {
251
if (last) {
252
last->next = curr->next;
253
free(curr);
254
curr = last->next;
255
} else {
256
newTrackedVal->instances = curr->next;
257
free(curr);
258
curr = newTrackedVal->instances;
259
}
260
newTrackedVal->candidates--;
261
if (newTrackedVal->candidates == 1) {
262
dprintf("[J] Value %s is stored at address 0x%08x\n",
263
newTrackedVal->valName, newTrackedVal->instances->address);
264
return;
265
}
266
} else {
267
last = curr; curr = curr->next;
268
}
269
}
270
dprintf("[J] Narrowed down address of %s to %d possible candidates.\n", name, newTrackedVal->candidates);
271
return;
272
}
273
dprintf("[J] Creating new list of candidates for %s.\n", name);
274
275
// Create a new list and search all memory for the value
276
newTrackedVal = (struct trackedVal *) malloc(sizeof (struct trackedVal));
277
if (newTrackedVal == NULL) {
278
dprintf("[J] OOM!");
279
return;
280
}
281
newTrackedVal->next = NULL;
282
newTrackedVal->valSize = size;
283
newTrackedVal->valName = _strdup(name);
284
if(!newTrackedVal->valName) {
285
free(newTrackedVal);
286
dprintf("[J] OOM!\n");
287
return;
288
}
289
290
newTrackedVal->candidates = findAllVals((BYTE*) &value, size, &(newTrackedVal->instances));
291
dprintf("[J] Discovered %d possible candidate addresses for %s\n", newTrackedVal->candidates, name);
292
293
newTrackedVal->next = trackedValList;
294
trackedValList = newTrackedVal;
295
296
return;
297
}
298
299
void bindJutsu(char *bindPort) {
300
HANDLE hThread;
301
DWORD dwThreadId;
302
IDebugOutputCallbacks *fuzzerOutputCallback;
303
304
// Initialize Request Queue
305
memset(&jutsuRequests, 0, sizeof (struct requestQueue));
306
307
// Fire up backchannel thread
308
hThread = CreateThread( NULL,
309
0,
310
listenJutsu,
311
(LPVOID) bindPort,
312
0,
313
&dwThreadId);
314
315
if (hThread == NULL)
316
dprintf("[Byakugan] CreateThread() failed.\n");
317
}
318
319
DWORD WINAPI listenJutsu(LPVOID lpvParam) {
320
WSADATA wsaData;
321
char recvbuf[DEFAULT_BUFLEN];
322
ULONG iResult, iSendResult;
323
ULONG recvbuflen = DEFAULT_BUFLEN;
324
char *bindPort = (char *) lpvParam;
325
struct addrinfo *result = NULL,
326
hints;
327
328
329
dprintf("[J] Creating Metasploit back channel on port %s... ", bindPort);
330
331
if (WSAStartup( MAKEWORD( 2, 2 ), &wsaData) != 0) {
332
dprintf("Failed!: %d\n", WSAGetLastError());
333
return (-1);
334
}
335
336
ZeroMemory(&hints, sizeof(hints));
337
hints.ai_family = AF_INET;
338
hints.ai_socktype = SOCK_STREAM;
339
hints.ai_protocol = IPPROTO_TCP;
340
hints.ai_flags = AI_PASSIVE;
341
342
// Resolve the server address and port
343
iResult = getaddrinfo(NULL, bindPort, &hints, &result);
344
if ( iResult != 0 ) {
345
dprintf("Failed!: %d\n", WSAGetLastError());
346
WSACleanup();
347
return (-1);
348
}
349
350
// Create a SOCKET for connecting to server
351
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
352
if (ListenSocket == INVALID_SOCKET) {
353
dprintf("Failed!: %d\n", WSAGetLastError());
354
freeaddrinfo(result);
355
WSACleanup();
356
return (-1);
357
}
358
359
// Setup the TCP listening socket
360
iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
361
if (iResult == SOCKET_ERROR) {
362
dprintf("Failed!: %d\n", WSAGetLastError());
363
freeaddrinfo(result);
364
closesocket(ListenSocket);
365
WSACleanup();
366
return (-1);
367
}
368
369
freeaddrinfo(result);
370
371
iResult = listen(ListenSocket, SOMAXCONN);
372
if (iResult == SOCKET_ERROR) {
373
dprintf("Failed!: %d\n", WSAGetLastError());
374
closesocket(ListenSocket);
375
WSACleanup();
376
return (-1);
377
}
378
379
dprintf("Listening.\n");
380
381
// Accept a client socket
382
ClientSocket = accept(ListenSocket, NULL, NULL);
383
if (ClientSocket == INVALID_SOCKET) {
384
dprintf("[J] Back channel accept failed: %d\n", WSAGetLastError());
385
closesocket(ListenSocket);
386
WSACleanup();
387
return (-1);
388
}
389
390
// No longer need server socket
391
closesocket(ListenSocket);
392
393
// Register new output callback
394
//fuzzerOutputCallback = new IDebugOutputCallbacks();
395
396
// Register new event callback
397
398
// Receive until the peer shuts down the connection
399
do {
400
memset(recvbuf, 0, DEFAULT_BUFLEN);
401
402
iResult = recv(ClientSocket, recvbuf, recvbuflen, 0);
403
if (iResult > 0)
404
parseJutsu(recvbuf, iResult);
405
else if (iResult == 0)
406
dprintf("[J] Back channel connection closing...\n");
407
else {
408
dprintf("[J] Back channel recv failed: %d\n", WSAGetLastError());
409
closesocket(ClientSocket);
410
WSACleanup();
411
return (-1);
412
}
413
} while (iResult > 0);
414
415
// shutdown the connection since we're done
416
iResult = shutdown(ClientSocket, SD_SEND);
417
if (iResult == SOCKET_ERROR) {
418
dprintf("[J] Back channel shutdown failed: %d\n", WSAGetLastError());
419
closesocket(ClientSocket);
420
WSACleanup();
421
return (-1);
422
}
423
424
// cleanup
425
closesocket(ClientSocket);
426
WSACleanup();
427
428
429
return (0);
430
}
431
432
void parseJutsu(char *buf, ULONG buflen) {
433
struct request *newRequest, *node;
434
struct requestHeader *reqHead;
435
436
//dprintf("[J] Back channel got: %s\n", buf);
437
438
reqHead = (struct requestHeader *) buf;
439
if ((reqHead->length + 4) > buflen || buflen < 5 || reqHead->length > 0xFFFD) {
440
dprintf("[J] Received a malformed jutsu request! :(\n");
441
return;
442
}
443
444
newRequest = (struct request *) malloc(sizeof (struct request));
445
if (newRequest == NULL) {
446
dprintf("[J] Failed to allocate! :(\n");
447
return;
448
}
449
450
newRequest->type = reqHead->type;
451
newRequest->length = reqHead->length;
452
newRequest->data = (BYTE *) malloc(newRequest->length + 1);
453
if (newRequest->data == NULL) {
454
dprintf("[J] Failed to allocate! :(\n");
455
free(newRequest);
456
return;
457
}
458
newRequest->next = NULL;
459
460
memcpy(newRequest->data, (buf+4), newRequest->length);
461
462
if (jutsuRequests.head != NULL) {
463
node = jutsuRequests.head;
464
while (node->next != NULL)
465
node = node->next;
466
node->next = newRequest;
467
} else {
468
jutsuRequests.head = newRequest;
469
}
470
jutsuRequests.length++;
471
472
return;
473
}
474
475
void showRequestsJutsu() {
476
struct request *node;
477
USHORT i;
478
479
dprintf("[J] Currently waiting on %d requests:\n", jutsuRequests.length);
480
481
node = jutsuRequests.head;
482
while (node != NULL) {
483
dprintf("Type: 0x%04x\tLength: 0x%04x\nData:",
484
node->type, node->length);
485
for (i = 0; i < node->length; i++) {
486
if (i % 32 == 0) dprintf("\n");
487
if (i % 8 == 0) dprintf("\t0x");
488
dprintf("%01x", node->data[i]);
489
}
490
dprintf("\n\n");
491
node = node->next;
492
}
493
}
494
void identBufJutsu(char *inputType, char *bufName, char *bufPatt, DWORD size, DWORD offset) {
495
struct trackedBuf *newTrackedBuf, *curBuf;
496
char *msfPattern;
497
DWORD readSize;
498
HANDLE hFile;
499
500
if (trackedBufList != NULL) {
501
curBuf = trackedBufList;
502
while (curBuf->next != NULL) {
503
if (!_stricmp(bufName, curBuf->bufName)) {
504
dprintf("[J] Buf %s already exists. Please delete it first.\n", bufName);
505
return;
506
}
507
curBuf = curBuf->next;
508
}
509
}
510
511
newTrackedBuf = (struct trackedBuf *) malloc(sizeof (struct trackedBuf));
512
if (newTrackedBuf == NULL) {
513
dprintf("[J] OOM!");
514
return;
515
}
516
517
newTrackedBuf->next = NULL;
518
newTrackedBuf->prev = NULL;
519
if (!_stricmp(inputType, "msfpattern")) {
520
size = strtoul(bufPatt, NULL, 10);
521
msfPattern = (char *) malloc(size+1);
522
if (msfPattern == NULL) {
523
dprintf("[J] Failed to allocate %d bytes!\n", size+1);
524
return;
525
}
526
msf_pattern_create(size, msfPattern);
527
msfPattern[size] = '\x00';
528
newTrackedBuf->bufPatt = msfPattern;
529
} else if (!_stricmp(inputType, "ascii")){
530
newTrackedBuf->bufPatt = _strdup(bufPatt);
531
size = strlen(bufPatt);
532
} else if (!_stricmp(inputType, "file")) {
533
readSize = readFileIntoBuf(bufPatt, size, &(newTrackedBuf->bufPatt), 0);
534
if ((size && readSize != size) || readSize == 0) {
535
dprintf("[J] Unable to read %d bytes from %s\n", size, bufName);
536
dprintf("\nThis command requires a buffer type, name, (sometimes) value, and size - maybe you forgot one?\n");
537
return;
538
}
539
size = (size ? size : readSize);
540
} else if (!_stricmp(inputType, "smartFile")) {
541
readSize = readFileIntoBuf(bufPatt, size, &(newTrackedBuf->bufPatt), offset);
542
if ((size && readSize != size) || readSize == 0) {
543
dprintf("[J] Unable to read %d bytes from %s\n", size, bufName);
544
dprintf("\nThis command requires a buffer type, name, (sometimes) value, and size - maybe you forgot one?\n");
545
return;
546
}
547
size = (size ? size : readSize);
548
}
549
550
551
newTrackedBuf->bufName = _strdup(bufName);
552
newTrackedBuf->bufSize = size;
553
if (newTrackedBuf->bufName == NULL || newTrackedBuf->bufPatt == NULL) {
554
dprintf("[J] OOM!");
555
return;
556
}
557
558
if (trackedBufList == NULL) {
559
trackedBufList = newTrackedBuf;
560
} else {
561
curBuf->next = newTrackedBuf;
562
newTrackedBuf->prev = curBuf;
563
}
564
dprintf("[J] Creating buffer %s.\n", bufName);
565
}
566
567
void rmBufJutsu(char *bufName) {
568
struct trackedBuf *curBuf;
569
570
curBuf = trackedBufList;
571
while (curBuf != NULL) {
572
if(!_stricmp(bufName, curBuf->bufName))
573
break;
574
curBuf = curBuf->next;
575
}
576
if (curBuf != NULL) {
577
if (curBuf->prev != NULL)
578
curBuf->prev->next = curBuf->next;
579
if (curBuf->next != NULL)
580
curBuf->next->prev = curBuf->prev;
581
if (curBuf == trackedBufList)
582
trackedBufList = curBuf->next;
583
free(curBuf->bufName);
584
free(curBuf->bufPatt);
585
free(curBuf);
586
dprintf("[J] Removed buffer: %s\n", bufName);
587
} else {
588
dprintf("[J] Unable to find buffer: %s\n", bufName);
589
}
590
}
591
592
void listTrackedBufJutsu() {
593
struct trackedBuf *curBuf;
594
DWORD i;
595
596
curBuf = trackedBufList;
597
if (curBuf == NULL) {
598
dprintf("[J] Currntly tracking no buffer patterns.\n");
599
} else {
600
dprintf("[J] Currently tracked buffer patterns:\n");
601
while (curBuf != NULL) {
602
dprintf("\tBuf: %s\tPattern: ", curBuf->bufName);
603
for (i = 0; i < curBuf->bufSize; i++)
604
dprintf("%c", curBuf->bufPatt[i]);
605
dprintf("\n");
606
curBuf = curBuf->next;
607
}
608
}
609
dprintf("\n");
610
}
611
612
void hunterJutsu() {
613
struct trackedBuf *curBuf;
614
struct bufInstance *instance;
615
ULONG i, j, range, addr, *nextNum, foundInstance;
616
BOOLEAN caught;
617
char *corUpper, *corLower, *corUni;
618
ULONG64 ptr = 0;
619
620
for (i = 0; regs[i] != NULL; i++) {
621
addr = GetExpression(regs[i]);
622
curBuf = trackedBufList;
623
caught = FALSE;
624
while (curBuf != NULL) {
625
range = curBuf->bufSize;
626
for (j = 0; j < range-3; j++) {
627
nextNum = (ULONG *) ((curBuf->bufPatt) + j);
628
if (addr != 0 && *nextNum == addr) {
629
dprintf("[J] Controlling %s with %s at offset %d.\n",
630
regs[i], curBuf->bufName, j);
631
caught = TRUE;
632
break;
633
}
634
}
635
curBuf = curBuf->next;
636
if (caught)
637
break;
638
}
639
640
}
641
642
// Now, find all instances of buffers in memory with a fuzzy match! :)
643
curBuf = trackedBufList;
644
while (curBuf != NULL) {
645
foundInstance = searchMemory((unsigned char *) curBuf->bufPatt,
646
(curBuf->bufSize > 32) ? 32 : curBuf->bufSize, &ptr);
647
if (foundInstance != 0) {
648
// try for larger increments
649
instance = (struct bufInstance *) malloc(sizeof (struct bufInstance));
650
memset(instance, 0, sizeof (struct bufInstance));
651
instance->address = foundInstance;
652
dprintf("[J] Found buffer %s @ 0x%08x\n", curBuf->bufName, foundInstance);
653
}
654
// try standard corruptions
655
range = (curBuf->bufSize > 32) ? 32 : curBuf->bufSize;
656
corUpper = (char *) malloc(range + 1);
657
corLower = (char *) malloc(range + 1);
658
corUni = (char *) malloc((range + 1) * 2);
659
for (i = j = 0; i < range; i++) {
660
corUpper[i] = (char) toupper(curBuf->bufPatt[i]);
661
corLower[i] = (char) tolower(curBuf->bufPatt[i]);
662
corUni[j++] = curBuf->bufPatt[i];
663
corUni[j++] = '\x00';
664
}
665
if ((foundInstance = searchMemory((unsigned char *) corUpper, range, &ptr)) != 0)
666
dprintf("[J] Found buffer %s @ 0x%08x - Victim of toUpper!\n",
667
curBuf->bufName, foundInstance);
668
if ((foundInstance = searchMemory((unsigned char *) corLower, range, &ptr)) != 0)
669
dprintf("[J] Found buffer %s @ 0x%08x - Victim of toLower!\n",
670
curBuf->bufName, foundInstance);
671
if ((foundInstance = searchMemory((unsigned char *) corUni, range*2, &ptr)) != 0)
672
dprintf("[J] Found buffer %s @ 0x%08x - Victim of Unicode Conversion!\n",
673
curBuf->bufName, foundInstance);
674
free(corUpper);
675
free(corLower);
676
free(corUni);
677
678
679
curBuf = curBuf->next;
680
}
681
682
}
683
684
ULONG64 allocateMemoryBlock(unsigned long size){
685
unsigned long processId = 0;
686
void * allocBuffer = 0;
687
ULONG Class;
688
ULONG Qualifier;
689
690
g_ExtControl->GetDebuggeeType(&Class, &Qualifier);
691
if (Class & DEBUG_CLASS_USER_WINDOWS) {
692
// USER LAND!
693
if(g_ExtSystem->GetCurrentProcessSystemId(&processId) != S_OK){
694
dprintf("[J] failed to find process id\n");
695
return 0;
696
}
697
698
if(!(processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId))){
699
dprintf("[J] OpenProcess failed\n");
700
return 0;
701
}
702
703
if(!(allocBuffer = VirtualAllocEx(processHandle, NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))){
704
dprintf("[J] VirtualAllocEx failed\n");
705
CloseHandle(processHandle);
706
return 0;
707
}
708
} else {
709
// KERNEL LAND!
710
711
}
712
//CloseHandle(processHandle);
713
714
return ((ULONG64)allocBuffer);
715
}
716
717
unsigned short getInstructionBytes(char * instruction, unsigned char * opcodeBuffer){
718
BYTE zero = 0;
719
BYTE byteCounter = 0;
720
ULONG64 byteEnd = 0;
721
BYTE i = 0;
722
723
if(!disassemblyBuffer){
724
if(!(disassemblyBuffer = allocateMemoryBlock(0x1000))){
725
dprintf("[J] allocateMemoryBlock failed\n");
726
return (0);
727
}
728
}
729
730
731
if(g_ExtControl->Assemble(disassemblyBuffer, instruction, &byteEnd) != S_OK){
732
dprintf("[J] failed to assemble instruction\n");
733
return (0);
734
}
735
736
if(!ReadMemory(disassemblyBuffer, opcodeBuffer, (byteEnd-disassemblyBuffer), NULL)){
737
dprintf("[J] failed to read opcode sequence\n");
738
return (0);
739
}
740
741
for(i=0; i<(byteEnd-disassemblyBuffer); i++){
742
if(!WriteMemory((disassemblyBuffer+i), &zero, 1, NULL)){
743
dprintf("[J] failed to zero memory\n");
744
return (0);
745
}
746
}
747
#if 0
748
dprintf("[J] Opcode sequence for instruction %s:", instruction);
749
750
for(byteCounter=0; ((disassemblyBuffer+byteCounter)<byteEnd); byteCounter++){
751
dprintf("%02x ", opcodeBuffer[byteCounter]);
752
}
753
754
dprintf("\n");
755
#endif
756
return (byteEnd-disassemblyBuffer);
757
}
758
759
ULONG64 searchMemory(unsigned char * byteBuffer, unsigned long length, ULONG64 *addressHit){
760
HRESULT memSearch = S_OK;
761
762
if((memSearch = g_ExtData->SearchVirtual((ULONG64)*addressHit, (ULONG64)-1, byteBuffer,
763
length, 1, addressHit)) != S_OK){
764
#if 0
765
if(memSearch == HRESULT_FROM_NT(STATUS_NO_MORE_ENTRIES)){
766
dprintf("[J] byte sequence not found in virtual memory\n");
767
}
768
else{
769
dprintf("[J] byte search failed for another reason\n");
770
}
771
#endif
772
return (0);
773
}
774
return (*addressHit);
775
}
776
777
DWORD findAllVals(unsigned char *byteBuffer, BYTE size, struct valInstance **instance) {
778
ULONG64 addressHit = 0;
779
DWORD addressCount = 0;
780
HRESULT memSearch;
781
struct valInstance *newValInstance;
782
783
*instance = NULL;
784
785
while ((memSearch = g_ExtData->SearchVirtual(addressHit+size, (ULONG64)-1, byteBuffer,
786
size, 1, &addressHit)) == S_OK) {
787
788
if (!*instance) {
789
*instance = (struct valInstance *) malloc(sizeof (struct valInstance));
790
newValInstance = *instance;
791
} else {
792
newValInstance->next = (struct valInstance *) malloc(sizeof (struct valInstance));
793
newValInstance = newValInstance->next;
794
}
795
newValInstance->address = addressHit;
796
newValInstance->next = NULL;
797
addressCount++;
798
}
799
800
return (addressCount);
801
}
802
803
BOOL checkExecutability(ULONG64 checkAddress){
804
MEMORY_BASIC_INFORMATION protectionInfo;
805
806
if(!VirtualQueryEx(processHandle, (LPVOID)checkAddress, &protectionInfo, sizeof(MEMORY_BASIC_INFORMATION))){
807
dprintf("[J] Unable to obtain protection information for address 0x%08x\n", checkAddress);
808
return FALSE;
809
}
810
811
//dprintf("allocation info: 0x%08x and 0x%08x\n", protectionInfo.AllocationProtect, protectionInfo.Protect);
812
813
if((protectionInfo.Protect & PAGE_EXECUTE_READ) != 0)
814
return TRUE;
815
816
//dprintf("[J] 0x%08x isn't executable\n");
817
return FALSE;
818
}
819
820
void searchOpcodes(char *instructions) {
821
char **instructionList;
822
unsigned char *byteSequence;
823
DWORD length, i, j, semiCount = 1, offset = 0;
824
ULONG64 ptr = 0;
825
826
// Split instructions into seperate strings at pipes
827
length = 0;
828
while (instructions[length] != NULL) {
829
if (instructions[length] == '|')
830
semiCount++;
831
length++;
832
}
833
834
// Malloc space for instructionList;
835
instructionList = (char **) malloc((semiCount+1) * sizeof (char *));
836
if (instructionList == NULL) {
837
dprintf("[J] OOM!\n");
838
return;
839
}
840
instructionList[0] = instructions;
841
dprintf("[J] Searching for:\n");
842
i = 0; j = 0;
843
while (i < length) {
844
if (instructions[i] == '|') {
845
instructions[i] = '\x00';
846
dprintf("> %s\n", instructionList[j++]);
847
instructionList[j] = &(instructions[i+1]);
848
}
849
i++;
850
}
851
dprintf("> %s\n", instructionList[j]);
852
853
854
// Allocate space for byteSequence
855
byteSequence = (unsigned char *) malloc(semiCount * 6);
856
if (byteSequence == NULL) {
857
dprintf("[J] OOM!\n");
858
return;
859
}
860
861
// Generate byte sequence and display it
862
for (i = 0; i < semiCount; i++) {
863
unsigned char tmpbuf[8];
864
offset += getInstructionBytes(instructionList[i], byteSequence+offset);
865
}
866
867
dprintf("[J] Machine Code:\n> ");
868
for (i = 0; i < offset; i++) {
869
dprintf("%02x ", byteSequence[i]);
870
if (i != 0 && !(i % 16))
871
dprintf("\n> ");
872
}
873
dprintf("\n");
874
875
// Search for sequence in executable memory
876
while((ptr = searchMemory(byteSequence, offset, &ptr)) != 0) {
877
if (ptr && checkExecutability(ptr)) {
878
dprintf("[J] Executable opcode sequence found at: 0x%08x\n", ptr);
879
}
880
ptr++;
881
}
882
return;
883
}
884
885
void searchVtptr(DWORD vtOffset, char *instructions) {
886
char **instructionList;
887
unsigned char *byteSequence;
888
DWORD length, i, j, semiCount = 1, offset = 0;
889
ULONG64 ptr = 0;
890
891
// Split instructions into seperate strings at pipes
892
length = 0;
893
while (instructions[length] != NULL) {
894
if (instructions[length] == '|')
895
semiCount++;
896
length++;
897
}
898
899
// Malloc space for instructionList;
900
instructionList = (char **) malloc((semiCount+1) * sizeof (char *));
901
if (instructionList == NULL) {
902
dprintf("[J] OOM!\n");
903
return;
904
}
905
instructionList[0] = instructions;
906
dprintf("[J] Searching for:\n");
907
i = 0; j = 0;
908
while (i < length) {
909
if (instructions[i] == '|') {
910
instructions[i] = '\x00';
911
dprintf("> %s\n", instructionList[j++]);
912
instructionList[j] = &(instructions[i+1]);
913
}
914
i++;
915
}
916
dprintf("> %s\n", instructionList[j]);
917
918
919
// Allocate space for byteSequence
920
byteSequence = (unsigned char *) malloc(semiCount * 6);
921
if (byteSequence == NULL) {
922
dprintf("[J] OOM!\n");
923
return;
924
}
925
926
// Generate byte sequence and display it
927
for (i = 0; i < semiCount; i++) {
928
unsigned char tmpbuf[8];
929
offset += getInstructionBytes(instructionList[i], byteSequence+offset);
930
}
931
932
dprintf("[J] Machine Code:\n> ");
933
for (i = 0; i < offset; i++) {
934
dprintf("%02x ", byteSequence[i]);
935
if (i != 0 && !(i % 16))
936
dprintf("\n> ");
937
}
938
dprintf("\n");
939
940
// Search for sequence in executable memory
941
while((ptr = searchMemory(byteSequence, offset, &ptr)) != 0) {
942
if (ptr && checkExecutability(ptr)) {
943
ULONG64 copyPtr = 0, otherPtr = ptr;
944
//dprintf("[J] Executable opcode sequence found at: 0x%08x\n", ptr);
945
while((copyPtr = searchMemory((unsigned char *)&otherPtr, 4, &copyPtr)) != 0) {
946
ULONG64 fptr = 0, vtPtr = copyPtr-vtOffset;
947
//dprintf("\tPtr @ 0x%08x\n", copyPtr);
948
while((fptr = searchMemory((unsigned char *)&vtPtr, 4, &fptr)) != 0) {
949
//dprintf("\t\tvTable Ptr @ 0x%08x\n", vtPtr);
950
dprintf("0x%08x -> 0x%08x -> 0x%08x -> sequence\n",
951
(ULONG)fptr, (ULONG)vtPtr, (ULONG)otherPtr);
952
fptr++;
953
}
954
copyPtr++;
955
}
956
}
957
ptr++;
958
}
959
return;
960
}
961
962
void returnAddressHuntJutsu(){
963
struct trackedBuf *curBuf;
964
int i = 0, bufferIndex = 0;
965
ULONG offset = 0, bytes = 0;
966
char findBufferExpression[25];
967
ULONG64 returnAddress = 0, ptr = 0;
968
HRESULT memSearch = S_OK;
969
970
//disassembly variables
971
char returnInstruction[30];
972
unsigned char opcodeBuffer[30];
973
unsigned short instructionLength = 0;
974
dprintf("[J] started return address hunt\n");
975
976
977
for(i; i<6; i++){ //6, because we don't want to waste time on the eip register
978
curBuf = trackedBufList;
979
memset(findBufferExpression, 0x00, sizeof(findBufferExpression));
980
981
if(!(bytes = GetExpression(regs[i]))){
982
dprintf("[J] skipping %s as register - it is a null pointer\n", regs[i]);
983
continue;
984
}
985
986
StringCchPrintf(findBufferExpression, sizeof(findBufferExpression), "poi(%s)", regs[i]);
987
bytes = GetExpression(findBufferExpression);
988
989
//tests if a register points to a location in user controlled data
990
while(curBuf != NULL){
991
for(bufferIndex=0; bufferIndex < curBuf->bufSize; bufferIndex++){
992
if(*(PULONG)((curBuf->bufPatt)+bufferIndex) == bytes){
993
memset(opcodeBuffer, 0x00, sizeof(opcodeBuffer));
994
memset(returnInstruction, 0x00, sizeof(returnInstruction));
995
996
//find the opcodes for the desired instruction
997
998
//first, for call reg
999
StringCchPrintf(returnInstruction, sizeof(returnInstruction), "call %s", regs[i]);
1000
if(!(instructionLength = getInstructionBytes(returnInstruction, opcodeBuffer)))
1001
dprintf("[J] getInstructionBytes failed for '%s'\n", returnInstruction);
1002
if(returnAddress = searchMemory(opcodeBuffer, instructionLength, &ptr)){
1003
if(checkExecutability(returnAddress))
1004
dprintf("[J] valid return address (call %s) found at 0x%08x\n", regs[i], returnAddress);
1005
}
1006
1007
1008
//now, for jmp reg
1009
memset(returnInstruction, 0x00, sizeof(returnInstruction));
1010
StringCchPrintf(returnInstruction, sizeof(returnInstruction), "jmp %s", regs[i]);
1011
if(!(instructionLength = getInstructionBytes(returnInstruction, opcodeBuffer)))
1012
dprintf("[J] getInstructionBytes failed for '%s'\n", returnInstruction);
1013
if(returnAddress = searchMemory(opcodeBuffer, instructionLength, &ptr)){
1014
if(checkExecutability(returnAddress))
1015
dprintf("[J] valid return address (jmp %s) found at 0x%08x\n", regs[i], returnAddress);
1016
}
1017
}
1018
}
1019
curBuf = curBuf->next;
1020
}
1021
1022
curBuf = trackedBufList;
1023
1024
for(offset=0; offset<0x1000; offset+=4){
1025
memset(findBufferExpression, 0x00, sizeof(findBufferExpression));
1026
StringCchPrintf(findBufferExpression, sizeof(findBufferExpression), "poi(poi(%s+0x%08x))", regs[i], offset);
1027
if(!(bytes = GetExpression(findBufferExpression)))
1028
continue; //this is basically a replacement for the
1029
//ddp windbg command, except more automated
1030
//walk through the buffer to see if any dword in there matches the current
1031
//value returned by the expression
1032
while(curBuf != NULL){
1033
for(bufferIndex=0; bufferIndex < curBuf->bufSize; bufferIndex++){
1034
if(*(PULONG)((curBuf->bufPatt)+bufferIndex) == bytes){
1035
memset(opcodeBuffer, 0x00, sizeof(opcodeBuffer));
1036
memset(returnInstruction, 0x00, sizeof(returnInstruction));
1037
dprintf("[J] %s + 0x%08x points into offset 0x%x of buffer %s\n",
1038
regs[i], offset, bufferIndex, curBuf->bufName);
1039
1040
1041
//first, build the instruction to find the bytes for
1042
//for now, we will support jmp [reg+offset] and call [reg+offset]
1043
1044
//first, for call [reg+offset]
1045
StringCchPrintf(returnInstruction, sizeof(returnInstruction), "call [%s+%x]", regs[i], offset);
1046
if(!(instructionLength = getInstructionBytes(returnInstruction, opcodeBuffer)))
1047
dprintf("[J] getInstructionBytes failed for '%s'\n", returnInstruction);
1048
if(returnAddress = searchMemory(opcodeBuffer, instructionLength, &ptr)){
1049
if(checkExecutability(returnAddress))
1050
dprintf("[J] valid return address (call [%s+%x]) found at 0x%08x\n", regs[i], offset, returnAddress);
1051
}
1052
1053
1054
//now, for jmp [reg+offset]
1055
memset(returnInstruction, 0x00, sizeof(returnInstruction));
1056
StringCchPrintf(returnInstruction, sizeof(returnInstruction), "jmp [%s+%x]", regs[i], offset);
1057
if(!(instructionLength = getInstructionBytes(returnInstruction, opcodeBuffer)))
1058
dprintf("[J] getInstructionBytes failed for '%s'\n", returnInstruction);
1059
if(returnAddress = searchMemory(opcodeBuffer, instructionLength, &ptr)){
1060
if(checkExecutability(returnAddress))
1061
dprintf("[J] valid return address (jmp [%s+%x]) found at 0x%08x\n", regs[i], offset, returnAddress);
1062
}
1063
}
1064
}
1065
curBuf = curBuf->next;
1066
}
1067
curBuf = trackedBufList;
1068
}
1069
}
1070
}
1071
1072