├── .gitignore
├── README.md
├── afl_bridge_external
├── Makefile
├── afl_bridge_external.c
└── types.h
├── examples
├── ppc
│ ├── bin
│ │ └── keygenme_ppc.elf
│ └── fuzz_ppc_check_serial.py
└── xtensa
│ ├── bin
│ └── keygenme_xtensa.elf
│ └── fuzz_xtensa_check_serial.py
├── fuzz_ppc_check_serial.py
├── fuzz_xtensa_check_serial.py
├── libAFL
├── __init__.py
└── libAFL.py
└── libUtils
├── __init__.py
└── libUtils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .pyc
2 | .class
3 | .log
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # afl_ghidra_emu
2 | [](https://opensource.org/licenses/Apache-2.0)
3 |
4 | afl_ghidra_emu is no longer maintained and replaced by **[Ghidralligator](https://github.com/airbus-cyber/ghidralligator). Try it!**
5 |
6 | afl_ghidra_emu allows to fuzz exotic architecture using AFL++ and Ghidra emulation with code coverage functionality.
7 |
8 | For more information, read this [article](https://github.com/airbus-cyber/blogpost/tree/main/fuzzing-exotic-arch-with-afl-using-ghidra-emulator).
9 |
10 |
11 |
12 |
13 |
14 |
15 | ## How it works?
16 |
17 | AFL++ runs a trampoline program (afl_bridge_external) which is in charge of forwarding samples to Ghidra emulation
18 | via a TCP socket (Ex: 127.0.0.1:6674/tcp).
19 |
20 | A python script in Ghidra (fuzz_xtensa_check_serial.py) is responsible for emulating code execution. It listens
21 | on a TCP socket (127.0.0.1:6674/tcp) and waits for input data coming from trampoline script.
22 | As soon as the script receives input data, the emulation will be started. During the execution, the executed path addresses,
23 | and the execution status are sent to afl_bridge_external using established TCP socket.
24 |
25 | afl_bridge_external reports the execution status and execution path to AFL++ using pipes and shared memory.
26 |
27 |
28 | ## Installation
29 | Install [AFL++](https://github.com/AFLplusplus/AFLplusplus)
30 |
31 | Clone afl_ghidra_emu directory
32 | ```bash
33 | git clone https://github.com/airbus-cyber/afl_ghidra_emu.git
34 | ```
35 |
36 | Compile afl_bridge_external
37 | ```
38 | cd afl_ghidra_emu/afl_bridge_external
39 | make
40 | ```
41 |
42 | Copy afl_ghidra_emu files to your ghidra script directory
43 | ```bash
44 | cd ../..
45 | cp –r afl_ghidra_emu/* $USER_HOME/ghidra_scripts/
46 | ```
47 |
48 | ## Example: Fuzzing Xtensa binary code keygenme_xtensa.elf
49 | ./examples/xtensa/bin/keygenme_xtensa.elf is a *keygenMe* compiled for Xtensa (ex: esp32) architecture.
50 | Xtensa is not officially supported in Ghidra yet. So, you need first to install it by following these [instruction](https://github.com/Ebiroll/ghidra-xtensa)
51 |
52 |
53 | #### Load in Ghidra
54 | - Create a new project in Ghidra;
55 | - Import file ./bin/keygenme_xtensa.elf (arch: Xtensa:LE:32);
56 | - Open it in CodeBrowser and execute auto-analyze;
57 | - Open Script Manager in "Window" submenu;
58 | - Run script fuzz_xtensa_check_serial.py;
59 |
60 |
61 |
62 | #### Start Fuzz
63 | Make AFL workspace directories
64 | ```bash
65 | mkdir input output
66 | ```
67 |
68 | Add first sample
69 | ```bash
70 | echo -n "BBBBBBBB" > input/sample1.bin
71 | ```
72 |
73 | Start AFL++ with trampoline program.
74 | ```bash
75 | afl-fuzz -D -i input -o output afl_bridge_external 127.0.0.1 6674 20
76 | ```
77 |
78 | #### Stop Ghidra emulation
79 | Stop AFL++ using CTRL+C. If Ghidra emulation still running, we can send "STOP" command:
80 | ```bash
81 | echo -e "\xff" | nc 127.0.0.1 6674
82 | ```
83 | Do no use Ghidra Cancel button, because it does not properly close the socket.
84 |
85 | ## Example: Fuzzing PPC binary code keygenme_ppc.elf
86 | ./examples/ppc/bin/keygenme_ppc.elf is also a *keygenMe* compiled for PowerPC architecture.
87 |
88 | Follow the same steps above with PowerPC:BE:32:default architecture in Ghidra and run the script fuzz_ppc_check_serial.py.
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/afl_bridge_external/Makefile:
--------------------------------------------------------------------------------
1 | all: afl_bridge_external
2 |
3 | afl_bridge_external: afl_bridge_external.c
4 | $(CC) -I../../include -o afl_bridge_external afl_bridge_external.c
5 |
6 | clean:
7 | rm -f afl_bridge_external *~ core
8 |
--------------------------------------------------------------------------------
/afl_bridge_external/afl_bridge_external.c:
--------------------------------------------------------------------------------
1 | /*
2 | american fuzzy lop++ - afl_brifge_external
3 | ---------------------------------------------------
4 |
5 | Written by Flavian Dola
6 |
7 | Copyright 2021 by Airbus CyberSecurity. All rights reserved.
8 | Copyright 2019-2020 AFLplusplus Project. All rights reserved.
9 |
10 | Adapted from afl_proxy (https://github.com/AFLplusplus/AFLplusplus/blob/stable/utils/afl_proxy/afl-proxy.c)
11 |
12 | Licensed under the Apache License, Version 2.0 (the "License");
13 | you may not use this file except in compliance with the License.
14 | You may obtain a copy of the License at:
15 |
16 | http://www.apache.org/licenses/LICENSE-2.0
17 |
18 |
19 | */
20 |
21 | #include "types.h"
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 |
40 |
41 | #define FORKSRV_FD 198
42 | #define MAP_SIZE_POW2 16
43 | #define MAP_SIZE (1U << MAP_SIZE_POW2)
44 | #define SHM_ENV_VAR "__AFL_SHM_ID"
45 |
46 | u8 *__afl_area_ptr;
47 | u32 __afl_map_size = MAP_SIZE;
48 |
49 | unsigned long afl_prev_loc = 0;
50 | int isSocketServerRunning = 0;
51 | int sockfd = -1;
52 | int connfd = -1;
53 | FILE* logfd;
54 | u32 id_sample = 0;
55 |
56 |
57 | #define CONFIG 0x2
58 |
59 | #define TRACE 0x3
60 | #define STOP 0xff
61 | #define CRASH 0xfe
62 | #define END 0xfd
63 | #define ERR 0xfc
64 |
65 |
66 | #define EXEC_END_OK 1
67 | #define EXEC_CRASH 2
68 | #define EXEC_ERR -1
69 | #define EXEC_UNK -2
70 |
71 |
72 |
73 | #define CLOSE_SOCKET(sock)({if (sock != -1) {close(sock); sock = -1;} })
74 | #define MAX_SZ_SAMPLE 0x7fff
75 | #define SA struct sockaddr
76 |
77 |
78 |
79 |
80 |
81 |
82 | /* Error reporting to forkserver controller */
83 |
84 | void send_forkserver_error(int error) {
85 |
86 | u32 status;
87 | if (!error || error > 0xffff) return;
88 | status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
89 | if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) return;
90 |
91 | }
92 |
93 | /* SHM setup. */
94 |
95 |
96 |
97 | static void __afl_map_shm(void) {
98 |
99 | char *id_str = getenv(SHM_ENV_VAR);
100 | char *ptr;
101 |
102 | /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then
103 | uncomment the following: */
104 |
105 | /*
106 | if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) {
107 |
108 | u32 val = atoi(ptr);
109 | if (val > 0) __afl_map_size = val;
110 |
111 | }
112 |
113 | */
114 |
115 | if (__afl_map_size > MAP_SIZE) {
116 |
117 | if (__afl_map_size > FS_OPT_MAX_MAPSIZE) {
118 |
119 | fprintf(stderr,
120 | "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u to "
121 | "be able to run this instrumented program!\n",
122 | __afl_map_size);
123 | if (id_str) {
124 |
125 | send_forkserver_error(FS_ERROR_MAP_SIZE);
126 | exit(-1);
127 |
128 | }
129 |
130 | } else {
131 |
132 | fprintf(stderr,
133 | "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u to "
134 | "be able to run this instrumented program!\n",
135 | __afl_map_size);
136 |
137 | }
138 |
139 | }
140 |
141 | if (id_str) {
142 |
143 | #ifdef USEMMAP
144 | const char * shm_file_path = id_str;
145 | int shm_fd = -1;
146 | unsigned char *shm_base = NULL;
147 |
148 | /* create the shared memory segment as if it was a file */
149 | shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
150 | if (shm_fd == -1) {
151 |
152 | fprintf(stderr, "shm_open() failed\n");
153 | send_forkserver_error(FS_ERROR_SHM_OPEN);
154 | exit(1);
155 |
156 | }
157 |
158 | /* map the shared memory segment to the address space of the process */
159 | shm_base =
160 | mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
161 |
162 | if (shm_base == MAP_FAILED) {
163 |
164 | close(shm_fd);
165 | shm_fd = -1;
166 |
167 | fprintf(stderr, "mmap() failed\n");
168 | send_forkserver_error(FS_ERROR_MMAP);
169 | exit(2);
170 |
171 | }
172 |
173 | __afl_area_ptr = shm_base;
174 | #else
175 | u32 shm_id = atoi(id_str);
176 |
177 | __afl_area_ptr = shmat(shm_id, 0, 0);
178 |
179 | #endif
180 |
181 | if (__afl_area_ptr == (void *)-1) {
182 |
183 | send_forkserver_error(FS_ERROR_SHMAT);
184 | exit(1);
185 |
186 | }
187 |
188 | /* Write something into the bitmap so that the parent doesn't give up */
189 |
190 | __afl_area_ptr[0] = 1;
191 |
192 | }
193 |
194 | }
195 |
196 | /* Fork server logic. */
197 |
198 | static void __afl_start_forkserver(void) {
199 |
200 | u8 tmp[4] = {0, 0, 0, 0};
201 | u32 status = 0;
202 |
203 | if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
204 | status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
205 | if (status) status |= (FS_OPT_ENABLED);
206 | memcpy(tmp, &status, 4);
207 |
208 | /* Phone home and tell the parent that we're OK. */
209 |
210 | if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
211 |
212 | }
213 |
214 | static u32 __afl_next_testcase(u8 *buf, u32 max_len) {
215 |
216 | s32 status, res = 0xffffff;
217 |
218 | /* Wait for parent by reading from the pipe. Abort if read fails. */
219 | if (read(FORKSRV_FD, &status, 4) != 4) return 0;
220 |
221 | /* we have a testcase - read it */
222 | memset(buf, 0, max_len);
223 | status = read(0, buf, max_len);
224 |
225 | /* report that we are starting the target */
226 | if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0;
227 |
228 | return status;
229 |
230 | }
231 |
232 | static void __afl_end_testcase(int status) {
233 |
234 | //int status = 0xffffff;
235 |
236 | if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(1);
237 |
238 | }
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 | void clear_afl_trace()
249 | {
250 | afl_prev_loc = 0;
251 | }
252 |
253 |
254 |
255 | void afl_maybe_log(unsigned long cur_loc) {
256 |
257 | cur_loc = (cur_loc >> 4) ^ (cur_loc << 8);
258 | unsigned long afl_idx = cur_loc ^ afl_prev_loc;
259 | afl_idx &= __afl_map_size - 1;
260 | __afl_area_ptr[afl_idx]++;
261 |
262 | afl_prev_loc = cur_loc >> 1;
263 | }
264 |
265 |
266 | int flush_socket() {
267 | char c;
268 | int r = 1;
269 |
270 | while (r == 1) {
271 | r = recv(sockfd, &c, 1, SO_RCVTIMEO);
272 | }
273 | }
274 |
275 |
276 | int get_exec_info() {
277 |
278 | int r = 0;
279 | unsigned char buff[4];
280 | u32 rcv_id = 0;
281 |
282 |
283 | clear_afl_trace();
284 |
285 |
286 | for (;;) {
287 |
288 | r = recv(sockfd, buff, 1, 0);
289 | if (r != 1){
290 | fprintf(logfd, "get_exec_info: Error on recv\n");
291 | fflush(logfd);
292 | return(EXEC_ERR);
293 | }
294 |
295 | switch (buff[0]) {
296 | case END:
297 | r = recv(sockfd, &rcv_id, 4, 0);
298 | if (r != 4) {
299 | fprintf(logfd, "get_exec_info: (END) Error on rcv_id\n");
300 | fflush(logfd);
301 | return(EXEC_ERR);
302 | }
303 | if (rcv_id != id_sample) {
304 | fprintf(logfd, "get_exec_info: (END) rcv_id (%d) not match id_sample (%d)\n", rcv_id, id_sample);
305 | fflush(logfd);
306 | return(EXEC_ERR);
307 | }
308 |
309 | // Remote execution ended without a crash
310 | return(EXEC_END_OK);
311 |
312 |
313 | case CRASH:
314 | r = recv(sockfd, &rcv_id, 4, 0);
315 | if (r != 4) {
316 | fprintf(logfd, "get_exec_info: (CRASH) Error on rcv_id\n");
317 | fflush(logfd);
318 | return(EXEC_ERR);
319 | }
320 | if (rcv_id != id_sample) {
321 | fprintf(logfd, "get_exec_info: (CRASH) rcv_id (%d) not match id_sample (%d)\n", rcv_id, id_sample);
322 | fflush(logfd);
323 | return(EXEC_ERR);
324 | }
325 |
326 | // Remote execution ended with a crash
327 | return(EXEC_CRASH);
328 |
329 |
330 | case TRACE:
331 | r = recv(sockfd, &rcv_id, 4, 0);
332 | if (r != 4) {
333 | fprintf(logfd, "get_exec_info: (TRACE) Error on rcv_id\n");
334 | fflush(logfd);
335 | return(EXEC_ERR);
336 | }
337 | if (rcv_id != id_sample) {
338 | fprintf(logfd, "get_exec_info: (TRACE) rcv_id (%d) not match id_sample (%d)\n", rcv_id, id_sample);
339 | fflush(logfd);
340 | return(EXEC_ERR);
341 | }
342 |
343 |
344 | r = recv(sockfd, buff, 4, 0);
345 | if (r != 4) {
346 | fprintf(logfd, "get_exec_info: Error on get exec trace\n");
347 | fflush(logfd);
348 | return(EXEC_ERR);
349 | }
350 | afl_maybe_log(*(unsigned long*) buff);
351 | break;
352 |
353 | case ERR:
354 | if (rcv_id != id_sample) {
355 | fprintf(logfd, "get_exec_info: (ERR) error received\n");
356 | fflush(logfd);
357 | return(EXEC_ERR);
358 | }
359 |
360 | default:
361 | fprintf(logfd, "get_exec_info: Error unknown receive code: 0x%X\nn", buff[0]);
362 | fflush(logfd);
363 | return(EXEC_UNK);
364 |
365 | }
366 | }
367 | }
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 | int connect_to_ext(char* pIpAddress, u32 port, u32 timeout_ms) {
381 |
382 | struct sockaddr_in servaddr;
383 | int res = 0;
384 |
385 |
386 | sockfd = socket(AF_INET, SOCK_STREAM, 0);
387 | if (sockfd == -1) {
388 | fprintf(logfd, "socket creation failed...\n");
389 | fflush(logfd);
390 | return(res);
391 | }
392 |
393 | // set timeout
394 | struct timeval tv;
395 | tv.tv_sec = timeout_ms/1000;
396 | tv.tv_usec = (timeout_ms % 1000) * 1000;
397 | if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv) != 0) {
398 | fprintf(logfd, "setsockopt creation failed...\n");
399 | fflush(logfd);
400 | return(res);
401 | }
402 |
403 | bzero(&servaddr, sizeof(servaddr));
404 | // assign IP, PORT
405 | servaddr.sin_family = AF_INET;
406 | servaddr.sin_addr.s_addr = inet_addr(pIpAddress);
407 | servaddr.sin_port = htons(port);
408 |
409 | if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
410 | fprintf(logfd, "connection with the server failed...\n");
411 | fflush(logfd);
412 | CLOSE_SOCKET(sockfd);
413 | return(res);
414 | }
415 |
416 | res = 1;
417 |
418 | return res;
419 |
420 | }
421 |
422 |
423 | int send_all(void *data2send, size_t length) {
424 | int res = 0;
425 | char *ptr = (char*) data2send;
426 | while (length > 0)
427 | {
428 | int i = send(sockfd, ptr, length, 0);
429 | if (i < 1) {
430 | return(res);
431 | }
432 | ptr += i;
433 | length -= i;
434 | }
435 | res = 1;
436 | return(res);
437 |
438 | }
439 |
440 |
441 |
442 | int send_input_data(char* pInputData, u16 sz) {
443 | int res = 0;
444 | int offset = 0;
445 | char buf[1+4+sz+MAX_SZ_SAMPLE];
446 |
447 | memset(buf, 0, sizeof(buf));
448 |
449 |
450 | if (pInputData == 0)
451 | {
452 | return(res);
453 | }
454 |
455 | if (sz > MAX_SZ_SAMPLE) {
456 | sz = MAX_SZ_SAMPLE;
457 | }
458 |
459 | buf[offset] = CONFIG;
460 | offset++;
461 |
462 | *(u32*)(buf+offset) = id_sample;
463 | offset = offset + sizeof(u32);
464 |
465 | *(u16*)(buf+offset) = sz;
466 | offset = offset + sizeof(u16);
467 | memcpy(buf+offset, pInputData, sz);
468 |
469 | if (1 != send_all(buf, offset+sz))
470 | {
471 | fprintf(logfd, "send_input_data: Send failed\n");
472 | fflush(logfd);
473 | return(res);
474 | }
475 |
476 |
477 | /* Write something into the bitmap so that the parent doesn't give up */
478 | __afl_area_ptr[0] = 1;
479 |
480 | res = 1;
481 | return(res);
482 | }
483 |
484 |
485 | void exit_with_segfault() {
486 | kill(getpid(), SIGSEGV);
487 | sleep(5);
488 | }
489 |
490 |
491 |
492 |
493 | void print_usage() {
494 | fprintf(stderr, "USAGE:\n afl_bridge_external IP PORT timeout_ms\n");
495 | fprintf(logfd, "USAGE:\n afl_bridge_external IP PORT timeout_ms\n");
496 | fflush(logfd);
497 | return;
498 | }
499 |
500 |
501 |
502 | int main(int argc, char *argv[]) {
503 |
504 | /* This is were the testcase data is written into */
505 | u8 buf[MAX_SZ_SAMPLE];
506 | s32 len;
507 | int res_exec = 0;
508 |
509 | // log to log
510 | logfd = fopen("./afl_bridge_external.log", "a");
511 | if (logfd == 0) {
512 | fprintf(stderr, "Error open log file\n");
513 | goto END_MAIN;
514 | }
515 |
516 | if (argc != 4)
517 | {
518 | fprintf(stderr, "Error: bad args\n");
519 | fprintf(logfd, "Error: bad args\n");
520 | print_usage();
521 | goto END_MAIN;
522 | }
523 |
524 | if (1 != connect_to_ext(argv[1], atoi(argv[2]), atoi(argv[3])) ) {
525 | fprintf(stderr, "Error: Failed to connect %s:%s\n", argv[1], argv[2]);
526 | fprintf(logfd, "Error: Failed to connect %s:%s\n", argv[1], argv[2]);
527 | fflush(logfd);
528 | goto END_MAIN;
529 | }
530 |
531 |
532 | /* here you specify the map size you need that you are reporting to
533 | afl-fuzz. Any value is fine as long as it can be divided by 32. */
534 | __afl_map_size = MAP_SIZE; // default is 65536
535 |
536 | /* then we initialize the shared memory map and start the forkserver */
537 | __afl_map_shm();
538 | __afl_start_forkserver();
539 |
540 | while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) {
541 | id_sample++;
542 |
543 | if (1 != send_input_data(buf, (u16)len)){
544 | fprintf(logfd, "Error on send input data\n");
545 | goto END_MAIN;
546 | }
547 |
548 |
549 | res_exec = get_exec_info();
550 | switch (res_exec)
551 | {
552 | case EXEC_ERR:
553 | fprintf(logfd, "EXEC_ERR: Error on collect execution info\n");
554 | fflush(logfd);
555 | //goto END_MAIN;
556 | // TODO: to improve....
557 | flush_socket();
558 | __afl_end_testcase(0x0);
559 | break;
560 | case EXEC_END_OK:
561 | // remote execution ended
562 | // no crash detect
563 | __afl_end_testcase(0x0);
564 | break;
565 | case EXEC_CRASH:
566 | // remote execution crashed
567 | // report to AFL
568 | //exit_with_segfault();
569 | __afl_end_testcase(0x0005);
570 | break;
571 | default:
572 | fprintf(logfd, "Unknown execution code %d\n", res_exec);
573 | fflush(logfd);
574 | goto END_MAIN;
575 | }
576 |
577 | }
578 |
579 | END_MAIN:
580 | fclose(logfd);
581 | CLOSE_SOCKET(sockfd);
582 |
583 | return 0;
584 |
585 | }
586 |
587 |
--------------------------------------------------------------------------------
/afl_bridge_external/types.h:
--------------------------------------------------------------------------------
1 | /*
2 | american fuzzy lop++ - type definitions and minor macros
3 | --------------------------------------------------------
4 |
5 | Originally written by Michal Zalewski
6 |
7 | Now maintained by Marc Heuse ,
8 | Heiko Eißfeldt ,
9 | Andrea Fioraldi ,
10 | Dominik Maier
11 |
12 | Copyright 2016, 2017 Google Inc. All rights reserved.
13 | Copyright 2019-2020 AFLplusplus Project. All rights reserved.
14 |
15 | Licensed under the Apache License, Version 2.0 (the "License");
16 | you may not use this file except in compliance with the License.
17 | You may obtain a copy of the License at:
18 |
19 | http://www.apache.org/licenses/LICENSE-2.0
20 |
21 | */
22 |
23 | #ifndef _HAVE_TYPES_H
24 | #define _HAVE_TYPES_H
25 |
26 | #include
27 | #include
28 |
29 | typedef uint8_t u8;
30 | typedef uint16_t u16;
31 | typedef uint32_t u32;
32 | #ifdef WORD_SIZE_64
33 | typedef unsigned __int128 uint128_t;
34 | typedef uint128_t u128;
35 | #endif
36 |
37 | /* Extended forkserver option values */
38 |
39 | /* Reporting errors */
40 | #define FS_OPT_ERROR 0xf800008f
41 | #define FS_OPT_GET_ERROR(x) ((x & 0x00ffff00) >> 8)
42 | #define FS_OPT_SET_ERROR(x) ((x & 0x0000ffff) << 8)
43 | #define FS_ERROR_MAP_SIZE 1
44 | #define FS_ERROR_MAP_ADDR 2
45 | #define FS_ERROR_SHM_OPEN 4
46 | #define FS_ERROR_SHMAT 8
47 | #define FS_ERROR_MMAP 16
48 |
49 | /* Reporting options */
50 | #define FS_OPT_ENABLED 0x80000001
51 | #define FS_OPT_MAPSIZE 0x40000000
52 | #define FS_OPT_SNAPSHOT 0x20000000
53 | #define FS_OPT_AUTODICT 0x10000000
54 | #define FS_OPT_SHDMEM_FUZZ 0x01000000
55 | #define FS_OPT_OLD_AFLPP_WORKAROUND 0x0f000000
56 | // FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
57 | #define FS_OPT_MAX_MAPSIZE ((0x00fffffeU >> 1) + 1)
58 | #define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
59 | #define FS_OPT_SET_MAPSIZE(x) \
60 | (x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
61 |
62 | typedef unsigned long long u64;
63 |
64 | typedef int8_t s8;
65 | typedef int16_t s16;
66 | typedef int32_t s32;
67 | typedef int64_t s64;
68 | #ifdef WORD_SIZE_64
69 | typedef __int128 int128_t;
70 | typedef int128_t s128;
71 | #endif
72 |
73 | #ifndef MIN
74 | #define MIN(a, b) \
75 | ({ \
76 | \
77 | __typeof__(a) _a = (a); \
78 | __typeof__(b) _b = (b); \
79 | _a < _b ? _a : _b; \
80 | \
81 | })
82 |
83 | #define MAX(a, b) \
84 | ({ \
85 | \
86 | __typeof__(a) _a = (a); \
87 | __typeof__(b) _b = (b); \
88 | _a > _b ? _a : _b; \
89 | \
90 | })
91 |
92 | #endif /* !MIN */
93 |
94 | #define SWAP16(_x) \
95 | ({ \
96 | \
97 | u16 _ret = (_x); \
98 | (u16)((_ret << 8) | (_ret >> 8)); \
99 | \
100 | })
101 |
102 | #define SWAP32(_x) \
103 | ({ \
104 | \
105 | u32 _ret = (_x); \
106 | (u32)((_ret << 24) | (_ret >> 24) | ((_ret << 8) & 0x00FF0000) | \
107 | ((_ret >> 8) & 0x0000FF00)); \
108 | \
109 | })
110 |
111 | #define SWAP64(_x) \
112 | ({ \
113 | \
114 | u64 _ret = (_x); \
115 | _ret = \
116 | (_ret & 0x00000000FFFFFFFF) << 32 | (_ret & 0xFFFFFFFF00000000) >> 32; \
117 | _ret = \
118 | (_ret & 0x0000FFFF0000FFFF) << 16 | (_ret & 0xFFFF0000FFFF0000) >> 16; \
119 | _ret = \
120 | (_ret & 0x00FF00FF00FF00FF) << 8 | (_ret & 0xFF00FF00FF00FF00) >> 8; \
121 | _ret; \
122 | \
123 | })
124 |
125 | // It is impossible to define 128 bit constants, so ...
126 | #ifdef WORD_SIZE_64
127 | #define SWAPN(_x, _l) \
128 | ({ \
129 | \
130 | u128 _res = (_x), _ret; \
131 | char *d = (char *)&_ret, *s = (char *)&_res; \
132 | int i; \
133 | for (i = 0; i < 16; i++) \
134 | d[15 - i] = s[i]; \
135 | u32 sr = 128U - ((_l) << 3U); \
136 | (_ret >>= sr); \
137 | (u128) _ret; \
138 | \
139 | })
140 | #endif
141 |
142 | #define SWAPNN(_x, _y, _l) \
143 | ({ \
144 | \
145 | char *d = (char *)(_x), *s = (char *)(_y); \
146 | u32 i, l = (_l)-1; \
147 | for (i = 0; i <= l; i++) \
148 | d[l - i] = s[i]; \
149 | \
150 | })
151 |
152 | #ifdef AFL_LLVM_PASS
153 | #if defined(__linux__) || !defined(__ANDROID__)
154 | #define AFL_SR(s) (srandom(s))
155 | #define AFL_R(x) (random() % (x))
156 | #else
157 | #define AFL_SR(s) ((void)s)
158 | #define AFL_R(x) (arc4random_uniform(x))
159 | #endif
160 | #else
161 | #if defined(__linux__) || !defined(__ANDROID__)
162 | #define SR(s) (srandom(s))
163 | #define R(x) (random() % (x))
164 | #else
165 | #define SR(s) ((void)s)
166 | #define R(x) (arc4random_uniform(x))
167 | #endif
168 | #endif /* ^AFL_LLVM_PASS */
169 |
170 | #define STRINGIFY_INTERNAL(x) #x
171 | #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
172 |
173 | #define MEM_BARRIER() __asm__ volatile("" ::: "memory")
174 |
175 | #if __GNUC__ < 6
176 | #ifndef likely
177 | #define likely(_x) (_x)
178 | #endif
179 | #ifndef unlikely
180 | #define unlikely(_x) (_x)
181 | #endif
182 | #else
183 | #ifndef likely
184 | #define likely(_x) __builtin_expect(!!(_x), 1)
185 | #endif
186 | #ifndef unlikely
187 | #define unlikely(_x) __builtin_expect(!!(_x), 0)
188 | #endif
189 | #endif
190 |
191 | #endif /* ! _HAVE_TYPES_H */
192 |
193 |
--------------------------------------------------------------------------------
/examples/ppc/bin/keygenme_ppc.elf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbus-cyber/afl_ghidra_emu/751c0df730b167630fb8ae84ff0dbeab365ce067/examples/ppc/bin/keygenme_ppc.elf
--------------------------------------------------------------------------------
/examples/ppc/fuzz_ppc_check_serial.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | """
4 | Copyright 2021 by Airbus CyberSecurity - Flavian Dola
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License");
7 | you may not use this file except in compliance with the License.
8 | You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS,
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | See the License for the specific language governing permissions and
16 | limitations under the License.
17 | """
18 |
19 |
20 | import struct
21 | import time
22 |
23 | from ghidra.app.emulator import EmulatorHelper
24 | from ghidra.program.model.address import GenericAddress
25 | from ghidra.util.task import ConsoleTaskMonitor
26 | from ghidra.program.model.block import BasicBlockModel
27 |
28 | from libAFL import libAFL
29 | from libUtils import libUtils
30 |
31 |
32 | # TCP listen PORT
33 | PORT = 6674
34 |
35 | DEBUG = False
36 |
37 | REG_FILTER = [
38 | "r1", "r2", "r3", "r4",
39 | "r9", "r31"
40 | ]
41 |
42 | D_REG = {
43 | "r1": "r1",
44 | "r2": "r2",
45 | "r3": "r3",
46 | "r4": "r4",
47 | "r9": "r9",
48 | "r31": "r31",
49 | }
50 |
51 |
52 |
53 |
54 | def write_memory(addr, data, sz = None):
55 | if type(addr) == GenericAddress:
56 | addr = libAFL.addr2int(addr)
57 | data_str = data
58 | if sz:
59 | if data < 0:
60 | raise ValueError("data must be positive")
61 | data_str = ""
62 | while data != 0:
63 | b = data & 0xff
64 | data_str += struct.pack("B", b)
65 | data = data >> 8
66 | i = 0
67 | while i < len(data_str):
68 | c = struct.unpack("B", data_str[i])[0]
69 | ghidra_addr = toAddr(addr+i)
70 | emuHelper.writeMemoryValue(ghidra_addr, 1, c)
71 | i += 1
72 | return
73 |
74 |
75 |
76 | def apply_hooks(emuHelper, addr, debug=False):
77 | """
78 | Apply hook if needed
79 | """
80 | # n_addr = get_next_execution_addr(addr)
81 |
82 | bRes = None
83 | addr_int = libUtils.addr2int(addr)
84 | if addr_int in D_HOOKS.keys():
85 | if debug:
86 | print(" * * * apply_hook: %s - %s" % (str(addr), D_HOOKS[addr_int]["name"]))
87 | bRes = D_HOOKS[addr_int]["callback"](emuHelper, addr)
88 |
89 | return bRes
90 |
91 |
92 |
93 | def hook_good_serial(emuHelper, addr):
94 | ret = emuHelper.readRegister("r3")
95 | if ret == 2:
96 | # force crash
97 | # => pc = 0
98 | emuHelper.writeRegister(emuHelper.getPCRegister(), 0x0)
99 | return True
100 | return False
101 |
102 |
103 | D_HOOKS = {
104 | 0x1000071c:{
105 | "name": "good_serial",
106 | "callback": hook_good_serial,
107 | },
108 | }
109 |
110 |
111 | if __name__ == '__main__':
112 |
113 | emuHelper = EmulatorHelper(currentProgram)
114 |
115 | monitor = ConsoleTaskMonitor()
116 | bbm = BasicBlockModel(currentProgram)
117 |
118 | ctx = {}
119 | ctx = libAFL.init_ctx(ctx, monitor, bbm)
120 |
121 | res, ctx = libAFL.run_bridge_server_api(ctx, port=PORT)
122 | if not res:
123 | print("Error on listen on %d tcp port", PORT)
124 | exit(1)
125 |
126 | start_addr = 0x1000063c
127 | stop_addr = toAddr(0x1000071c)
128 |
129 | # Add new memory section to store emulate values
130 | addr_section_emu = 0x20000000
131 | sz_emu = 0x100000
132 |
133 | pInput = addr_section_emu
134 |
135 | count = 0
136 | bFirstRun = True
137 |
138 | isRunning = True
139 | while isRunning:
140 |
141 | # reset previous block reached
142 | ctx = libAFL.init_ctx(ctx, monitor, bbm)
143 |
144 | res, ctx = libAFL.rcv_input(ctx, debug=DEBUG)
145 | if not res:
146 | if DEBUG:
147 | print("Error get config")
148 | res, ctx = libAFL.notify_err(ctx)
149 | continue
150 |
151 | if DEBUG:
152 | print("CONFIG: %s" % str(ctx))
153 |
154 | if libAFL.isStopOrder(ctx):
155 | isRunning = False
156 | break
157 |
158 | # Do some stats
159 | if count % 1000 == 0:
160 | count = 0
161 | if not bFirstRun:
162 | stat = 1000.0 / (time.time() - ref_time)
163 | print("Exec %d/s" % int(stat))
164 | bFirstRun = False
165 | ref_time = time.time()
166 | count += 1
167 |
168 | write_memory(pInput, libAFL.get_data_input(ctx))
169 | szInput = len(libAFL.get_data_input(ctx))
170 |
171 | # set register
172 | emuHelper.writeRegister("r3", pInput)
173 | emuHelper.writeRegister("r4", szInput)
174 | emuHelper.writeRegister(emuHelper.getPCRegister(), start_addr)
175 |
176 |
177 | # Emulation
178 | bCrash = False
179 | while True:
180 | if monitor.isCancelled():
181 | break
182 |
183 | executionAddress = emuHelper.getExecutionAddress()
184 |
185 |
186 | if apply_hooks(emuHelper, executionAddress):
187 | continue
188 |
189 |
190 | if (executionAddress in [stop_addr]):
191 | if DEBUG:
192 | print("Emulation complete.")
193 | break
194 |
195 |
196 | # Print current instruction and the registers we care about
197 |
198 | if DEBUG:
199 | print("\n%s: %s" % (str(executionAddress).upper(), getInstructionAt(executionAddress)))
200 |
201 | res, ctx = libAFL.notify_code_coverage(ctx, executionAddress, debug=DEBUG)
202 | if not res:
203 | print("Error on notify_code_coverage")
204 | isRunning = False
205 | break
206 |
207 | if DEBUG:
208 | for reg in REG_FILTER:
209 | reg_value = emuHelper.readRegister(reg)
210 | print("\t{} ({}) =\t{:08X}".format(reg, D_REG[reg], reg_value))
211 |
212 | # single step emulation
213 | success = emuHelper.step(monitor)
214 | if success == False:
215 | bCrash = True
216 | lastError = emuHelper.getLastError()
217 | print("Emulation Error: '{}'".format(lastError))
218 | break
219 |
220 | # End of Emulation
221 | if bCrash:
222 | res, ctx = libAFL.notify_crash(ctx)
223 | else:
224 | res, ctx = libAFL.notify_end_exec(ctx)
225 |
226 | if not res:
227 | # Error on notify
228 | break
229 |
230 | # End of prog
231 |
232 | ctx = libAFL.free_ctx(ctx)
233 |
234 |
235 |
--------------------------------------------------------------------------------
/examples/xtensa/bin/keygenme_xtensa.elf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbus-cyber/afl_ghidra_emu/751c0df730b167630fb8ae84ff0dbeab365ce067/examples/xtensa/bin/keygenme_xtensa.elf
--------------------------------------------------------------------------------
/examples/xtensa/fuzz_xtensa_check_serial.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | """
4 | Copyright 2021 by Airbus CyberSecurity - Flavian Dola
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License");
7 | you may not use this file except in compliance with the License.
8 | You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS,
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | See the License for the specific language governing permissions and
16 | limitations under the License.
17 | """
18 |
19 |
20 | import struct
21 |
22 | from ghidra.app.emulator import EmulatorHelper
23 | from ghidra.program.model.address import GenericAddress
24 | from ghidra.util.task import ConsoleTaskMonitor
25 | from ghidra.program.model.block import BasicBlockModel
26 |
27 | import time
28 |
29 | from libAFL import libAFL
30 |
31 | # TCP listen PORT
32 | PORT = 6674
33 |
34 | DEBUG = False
35 |
36 | REG_FILTER = [
37 | "a1", "a2", "a3", "a4",
38 | "a5", "a6", "a7", "a8",
39 | "a9"
40 | ]
41 |
42 | D_REG = {
43 | "a0": "a0",
44 | "a1": "a1",
45 | "a2": "a2",
46 | "a3": "a3",
47 | "a4": "a4",
48 | "a5": "a5",
49 | "a6": "a6",
50 | "a7": "a7",
51 | "a8": "a8",
52 | "a9": "a9",
53 | }
54 |
55 |
56 |
57 |
58 |
59 |
60 | def write_memory(addr, data, sz = None):
61 | if type(addr) == GenericAddress:
62 | addr = libAFL.addr2int(addr)
63 | data_str = data
64 | if sz:
65 | if data < 0:
66 | raise ValueError("data must be positive")
67 | data_str = ""
68 | while data != 0:
69 | b = data & 0xff
70 | data_str += struct.pack("B", b)
71 | data = data >> 8
72 | i = 0
73 | while i < len(data_str):
74 | c = struct.unpack("B", data_str[i])[0]
75 | ghidra_addr = toAddr(addr+i)
76 | emuHelper.writeMemoryValue(ghidra_addr, 1, c)
77 | i += 1
78 | return
79 |
80 |
81 |
82 | def apply_hooks(emuHelper, addr, debug=False):
83 | """
84 | Apply hook if needed
85 | """
86 | # n_addr = get_next_execution_addr(addr)
87 |
88 | bRes = None
89 | addr_int = libAFL.addr2int(addr)
90 | if addr_int in D_HOOKS.keys():
91 | if debug:
92 | print(" * * * apply_hook: %s - %s" % (str(addr), D_HOOKS[addr_int]["name"]))
93 | bRes = D_HOOKS[addr_int]["callback"](emuHelper, addr)
94 |
95 | return bRes
96 |
97 |
98 |
99 | def hook_good_serial(emuHelper, addr):
100 | ret = emuHelper.readRegister("a2")
101 | if ret == 2:
102 | # force crash
103 | # => pc = 0
104 | emuHelper.writeRegister(emuHelper.getPCRegister(), 0x0)
105 | return True
106 | return False
107 |
108 |
109 | D_HOOKS = {
110 | 0x400e3120:{
111 | "name": "good_serial",
112 | "callback": hook_good_serial,
113 | },
114 | }
115 |
116 |
117 | if __name__ == '__main__':
118 | emuHelper = EmulatorHelper(currentProgram)
119 |
120 | monitor = ConsoleTaskMonitor()
121 | bbm = BasicBlockModel(currentProgram)
122 |
123 | ctx = {}
124 | ctx = libAFL.init_ctx(ctx, monitor, bbm)
125 |
126 | res, ctx = libAFL.run_bridge_server_api(ctx, port=PORT)
127 | if not res:
128 | print("Error on listen on %d tcp port", PORT)
129 | exit(1)
130 |
131 | start_addr = 0x400e30ab
132 | stop_addr = toAddr(0x400e3120)
133 |
134 | # Add new memory section to store emulate values
135 | addr_section_emu = 0x20000000
136 | sz_emu = 0x100000
137 |
138 | pInput = addr_section_emu
139 |
140 | count = 0
141 | bFirstRun = True
142 |
143 | isRunning = True
144 | while isRunning:
145 |
146 | # reset previous block reached
147 | ctx = libAFL.init_ctx(ctx, monitor, bbm)
148 |
149 | res, ctx = libAFL.rcv_input(ctx, debug=DEBUG)
150 | if not res:
151 | if DEBUG:
152 | print("Error get config")
153 | res, ctx = libAFL.notify_err(ctx)
154 | continue
155 |
156 | if DEBUG:
157 | print("CONFIG: %s" % str(ctx))
158 |
159 | if libAFL.isStopOrder(ctx):
160 | isRunning = False
161 | break
162 |
163 | # Do some stats
164 | if count % 1000 == 0:
165 | count = 0
166 | if not bFirstRun:
167 | stat = 1000.0 / (time.time() - ref_time)
168 | print("Exec %d/s" % int(stat))
169 | bFirstRun = False
170 | ref_time = time.time()
171 | count += 1
172 |
173 |
174 | write_memory(pInput, libAFL.get_data_input(ctx))
175 | szInput = len(libAFL.get_data_input(ctx))
176 |
177 | # set register
178 | emuHelper.writeRegister("a2", pInput)
179 | emuHelper.writeRegister("a3", szInput)
180 | emuHelper.writeRegister(emuHelper.getPCRegister(), start_addr)
181 |
182 |
183 | # Emulation
184 | bCrash = False
185 | while True:
186 | if monitor.isCancelled():
187 | break
188 |
189 | executionAddress = emuHelper.getExecutionAddress()
190 |
191 |
192 | if apply_hooks(emuHelper, executionAddress):
193 | continue
194 |
195 |
196 | if (executionAddress in [stop_addr]):
197 | if DEBUG:
198 | print("Emulation complete.")
199 | break
200 |
201 |
202 | # Print current instruction and the registers we care about
203 |
204 | if DEBUG:
205 | print("\n%s: %s" % (str(executionAddress).upper(), getInstructionAt(executionAddress)))
206 |
207 | res, ctx = libAFL.notify_code_coverage(ctx, executionAddress, debug=DEBUG)
208 | if not res:
209 | print("Error on notify_code_coverage")
210 | isRunning = False
211 | break
212 |
213 | if DEBUG:
214 | for reg in REG_FILTER:
215 | reg_value = emuHelper.readRegister(reg)
216 | print("\t{} ({}) =\t{:08X}".format(reg, D_REG[reg], reg_value))
217 |
218 | # single step emulation
219 | success = emuHelper.step(monitor)
220 | if success == False:
221 | bCrash = True
222 | lastError = emuHelper.getLastError()
223 | print("Emulation Error: '{}'".format(lastError))
224 | break
225 |
226 | # End of Emulation
227 | if bCrash:
228 | res, ctx = libAFL.notify_crash(ctx)
229 | else:
230 | res, ctx = libAFL.notify_end_exec(ctx)
231 |
232 |
233 | # End of prog
234 |
235 | ctx = libAFL.free_ctx(ctx)
236 |
237 |
238 |
--------------------------------------------------------------------------------
/fuzz_ppc_check_serial.py:
--------------------------------------------------------------------------------
1 | examples/ppc/fuzz_ppc_check_serial.py
--------------------------------------------------------------------------------
/fuzz_xtensa_check_serial.py:
--------------------------------------------------------------------------------
1 | examples/xtensa/fuzz_xtensa_check_serial.py
--------------------------------------------------------------------------------
/libAFL/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/libAFL/libAFL.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2
2 |
3 | """
4 | Copyright 2021 by Airbus CyberSecurity - Flavian Dola
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License");
7 | you may not use this file except in compliance with the License.
8 | You may obtain a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS,
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | See the License for the specific language governing permissions and
16 | limitations under the License.
17 | """
18 |
19 |
20 | import struct
21 | import socket
22 | from libUtils import libUtils
23 |
24 |
25 |
26 | CONFIG = "\x02"
27 |
28 | TRACE = "\x03"
29 | STOP = "\xff"
30 | CRASH = "\xfe"
31 | END = "\xfd"
32 | ERR = "\xfc"
33 |
34 |
35 |
36 |
37 |
38 |
39 | def run_bridge_server_api(ctx, host="127.0.0.1", port=6666):
40 | res = False
41 | s_bridge = None
42 | try:
43 | s_bridge = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
44 | s_bridge.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
45 | s_bridge.bind((host, port))
46 | s_bridge.listen(1)
47 | ctx.update({"sock_bridge": s_bridge})
48 | res = True
49 | except Exception as e:
50 | print("run_bridge_server_api failed: %s" % str(e))
51 | if s_bridge is not None:
52 | s_bridge.close()
53 |
54 | return res, ctx
55 |
56 |
57 |
58 | def parse_cmd(ctx, data, debug=False):
59 | res = False
60 |
61 |
62 | if len(data) < 1:
63 | # too short
64 | if debug:
65 | print("parse_cmd: Data too short: %d\n" % len(data))
66 | return res, ctx
67 |
68 | offset = 0
69 | if data[0] == CONFIG:
70 | offset += 1
71 | if len(data[offset:]) < 6:
72 | if debug:
73 | print("parse_cmd: data invalid length: %d\n" % len(data[offset:]))
74 | return res, ctx
75 |
76 | id_sample = struct.unpack("> 8
29 |
30 | api = FlatProgramAPI(emuHelper.getProgram())
31 | i = 0
32 | while i < len(data_str):
33 | c = struct.unpack("B", data_str[i])[0]
34 | ghidra_addr = api.toAddr(addr+i)
35 | emuHelper.writeMemoryValue(ghidra_addr, 1, c)
36 | i += 1
37 | del api
38 | return
39 |
40 |
41 |
42 | def get_string(emuHelper, addr):
43 | my_str = ""
44 | api = None
45 | if type(addr) != GenericAddress:
46 | api = FlatProgramAPI(emuHelper.getProgram())
47 | addr = api.toAddr(addr)
48 |
49 |
50 | while True:
51 | b = emuHelper.readMemoryByte(addr)
52 | if b == 0:
53 | break
54 | my_str += struct.pack("B", b)
55 | addr = addr.add(1)
56 |
57 | del api
58 | return my_str
59 |
60 |
61 |
62 | def apply_hooks(emuHelper, d_hooks, addr, debug=False):
63 | """
64 | Apply hook if needed
65 | """
66 | # n_addr = get_next_execution_addr(addr)
67 |
68 | bRes = None
69 | addr_int = addr2int(addr)
70 | if addr_int in d_hooks.keys():
71 | if debug:
72 | print(" * * * apply_hook: %s - %s" % (str(addr), d_hooks[addr_int]["name"]))
73 | bRes = d_hooks[addr_int]["callback"](emuHelper, addr)
74 |
75 | return bRes
76 |
77 |
78 | def get_next_execution_addr(addr):
79 | if type(addr) in [int, long]:
80 | addr = toAddr(addr)
81 | return getInstructionAfter(addr).address
--------------------------------------------------------------------------------