├── .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 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](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 --------------------------------------------------------------------------------