NEW CARDING CHAT IN TELEGRAM

AFL++ QEMU_NYX + CMPLOG = snapshot based, hypervisor, black-box fuzzing with roadblocks

Man

Professional
Messages
2,836
Reputation
5
Reaction score
448
Points
83
Привет всем!

Мотивационная часть

В эпоху информационного общества многие привычные понятия трансформируются, приобретают новую материальную форму - это неизбежное влияние эволюции.

Бытует мнение, что одним из основопологающих принципов новой эпохи является трансформация из количества в качество.
Это весьма резонно, ведь информации становится все больше и больше. Технологический прогресс ускоряется в геометрической прогрессии - а значит времени для усвоения новой информации становится все меньше и меньше.
А из этого следует не хитрый вывод, что дальнейшая судьба человека, общества, нации будет весьма сильно зависить от способности взаимодействия с информационным полем.
Мы не есть исключение. В институтах ученые, академики, доценты и аспиранты пишут научные труды, делятся ими с общественностью и так далее.
То, во что рано или поздно, частично или полностью, трансформируется вышеописанное - это информациооные ресурсы профильных назначений. Например Дамага.
К сожалению, люди забывают о безопасности. Забывают о ней что на уровне человека, что на уровне государства, что на уровне нашего с вами конкурса статей... =)
А жаль.

Введение

Я люблю фаззинг.
Можно смотреть вечно на три вещи: как горит огонь, как течет вода, и как AFL++ собирает карту покрытия =)
В контексте AFL++ режим NYX - это режим фаззинга на уровне гипервизора, который использует аппаратные возможности процессоров intel (а именно - intel_pt) для сбора покрытия базовых блоков.
То есть, если раньше мы использовали либо статическую инструментацию (на этапе компиляции), либо динамическую (на этапе выполнения), то тут инструментация не выполняется вообще.
Точнее в ней нету необходимости, т.к. аппаратные возможности процессора позволяют получить информацию о выполнении процессором инструкций ветвления (так называемые углы (edges)).
Это дает огромное преимущество в производительности.
Кроме того, используется технология отката снапшота к первичному состоянию. Это дает сразу два весомых преимущества.
Во первых - благодоря dirty pages - перезаписываются только те страницы памяти, которые были модифицированы в процессе итерации. То есть перезагружаются только нужные "пиксели", а не все "изображение".
Во вторых - благодоря откату всей системы включая ядро - фаззинг получается 100% детерменированным.
Но есть и ложка дегтя в бочке меда. А именно - так называемые roadblocks (подводные камни).
Смысл в том, что в ходе фаззинга в исследуемом приложении существуют логические числовых и строковых значений, констант, либо динамически сгенерированных.
Константы, теоретически, можно извлечь из приложения и создать словарь для фаззинга. Во всяком случае строчные. С числовыми будет уже сложнее, но тоже можно.
Однако, для динамических паттернов эта техника не подойдет. Прийдется реверсить приложение и патчить те места, которые требуют подобных значений.
Существует технология -> RedQueen <-
Это технология, простая как двери, которая позволяет в процессе выполнения программы инструментировать отдельные мнемоники, отвечающие за интересующие нас операции, и получить в итоге динамически созданный словарь для фаззинга.

Часть первая - анализируем существующее.

И так, начнем мы, пожалуй, с того, что уже есть.
Те, кто читал мои статьи раньше, знет о существовании cmplog. Кто не знает - это имплементация RedQueen для AFL++.

Для начала откроем файл https://github.com/AFLplusplus/qemu...f35b1bf6b4b/target/i386/tcg/translate.c#L1449

Это то, как инструментируются мнемоники сравнения выраженные через SUB:
1.png



Как мы видим они вызывают функцию afl_gen_compcov(), передают туда адрес инструкции, аргументы и размер операнда.

2.png



Адрес инструкции хешируется, и в зависимости от размера операнда вызывается нужная вспомогательная функция, которая уже и выполняет взаимодействие с картой cmplog.

3.png


Обратите внимание на поле shape в структуре headers. Она определена в файле

4.png


То есть это просто размер паттерна минус один.
Например для токена размером 1 байт (8 бит) shape будет равно 0.
Для токена в 2 байта - единице.
В 4 байта - трем.
Для 8 байт - семи.
Ну и наконец для строки длинной в 31 байт он будет равен 30.

Теперь посмотрим как инструментируются инструкции класса CALL. https://github.com/AFLplusplus/qemu...f35b1bf6b4b/target/i386/tcg/translate.c#L5186

5.png


Как видим, тут напрямую вызывается вспомогательная функция.

6.png


Внутри нее все тоже самое, хешируется указатель инструкции, в зависимости от архитектуры (и соглашения вызовов) добываются аргументы и их содержимое копируется в карту cmplog.

И так, это то, как работала старая реализация внутри qemu которая инструментировала программы динамечески.
Теперь же взглянем на то, как работает современная реализация в QEMU-NYX.


7.png


Для операций сравнения у нас появилась еще и мнемоника ADD.
Не используемые в моем случае соглашения о вызовах я закоментировал.

Забегая вперед, вот так выглядит у меня функция test_strcmp().
В оригинале она выглядит чуть иначе:

8.png


Разница не велика, но весома.

Вот так вот https://github.com/nyx-fuzz/QEMU-Ny...e912a2809fcba58e67df23dfd/nyx/redqueen.c#L872
выглядит инструментация для LEA.

для ADD.

для CMP.

Окей, с бэк-эндом разробрались, теперь займемся фронт-эндом.
На стороне AFL++ в случае выставления флага -c при запуске - фаззер создает новый экземпляр форксервера (новый процесс, и новую структуру в памяти) и переключается между основным и cmplog в процессе работы.
Точнее происходит это вот тут вот: https://github.com/AFLplusplus/AFLp...0bf15b67e8d972da601bb74b/src/afl-fuzz.c#L2550

9.png


Как видим - в случае cmplog структура fsrv просто дублируется. после чего поднимается новый инстанс.
Обратите внимание, что первым делом задается общий указатель на карту покрытия.
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
То есть карта покрытия будет единой на оба инстанса.
Для нас это важный момент, так как у нас, в режиме NYX, будет один инстанс.

Тут следует упомянуть, что в AFL++ вся информация хранится в структуре afl_state.

В ней есть два объекта afl_forkserver_t. Основной и для cmplog.
Внутри струкруты форксервера уже хранятся свои данные нужные инстансу.

Нужно еще разобраться как же происходит коммуникация между софтом. Для этого используется общий сегмент памяти shm.

На стороне AFL++

либо

в зависимости от реализации shm.

И что еще нужно знать про cmplog на стороне AFL++ так это то, как он запускается.

10.png


Функция common_fuzz_cmplog_stuff() вызывается всякий раз когда нам нужно заполнить карту cmplog значениями специфичными для интересующего нас инпута.
Её логика проста как угол дома - запись ввода и запуск итерации.

На стороне QEMU инициализация общего сегмента памяти выполняется вот так: https://github.com/AFLplusplus/qemu...9b3b701bf35b1bf6b4b/accel/tcg/cpu-exec.c#L354

11.png


И так, мы понимаем как работает фронтенд и бекенд для cmplog.
Теперь разберемся как работает NYX режим. На стороне AFL++ происходит все тоже самое что и для обычного фаззинга в режиме QEMU, только в качестве executor-a используется функция из библиотеки libnyx.
Библиотека libnyx - это дополнительний слой абстракции, между фронтом и бэком, предоставляющий унифицированный интерфейс.
Создан он, по всей видимости, для удобства. С его помощью можно построить свой фаззер просто вызывая нужные функции.
Давайте рассмотрим как его использование реализовано в AFL++

Сперва заглянем в файл заголовков: https://github.com/AFLplusplus/AFLp...5b67e8d972da601bb74b/include/forkserver.h#L62

12.png


В данном заголовке существует структура nyx_plugin_handler_t, которая описывает существующий на данный момент набор апи, который предоставляет интерфейс.
Я выделил функцию, которую нету в оригинальной версии. Ее мы добавим во второй части.

Инициализируется данная структура в функции afl_load_libnyx_plugin()

13.png


Опять таки, забегая вперед, на скриншоте видно, как я добавил новое апи nyx_option_set_redqueen_mode.

Сама же библиотека написана на rust. И нужное нам апи в ней есть:

Однако, не экспортируется:
В файле экспортов функция option_set_redqueen_mode не описана.

Часть вторая - портируем код.

При правильной планировке задач страдания разработчика сводятся к минимуму.
Я всегда вспоминаю ту буханку хлеба, из которой сделали троллейбус =)

И так, нам нужно перенести движёк cmplog из кему в кему, доработать libnyx, доработать AFL++ для взаимодействия с доработанной libnyx, доработать сам AFL++ для поддержки фаззигна в режиме CMPLOG + QEMU_NYX.
В первой части мы рассмотрели как инициализируется сегменг общей памяти в AFL++, помним как он подгружается на стороне QEMU.
Нам нужно найти место в QEMU_NYX где бы мы могли аккуратно разместить код инициализации shm сегмента, а так же двух хендлеров - строковых и цифровых. Еще нам потребуется функция для хеширования адреса.

Быстро прогрепав исходники по паттерну redqueen я нашел подходящего кандидата:
Тут можно разместить функцию, которая будет инициализировать shm. Но сперва ее нужно портировать. У меня это получилось вот так:

для файла nyx/redqueen.c
14.png


после чего я просто добавил setup_cmplog_map() перед вызовом init_redqueen_state();
Далее я дословно переписал cmplog_cmp()

15.png


Хотя этот switch стоило бы заменить на изящную v = size/8 - 1;

16.png


так же дословно был переписан и cmplog_rtn().

Теперь нужно добавить их в те места, где это необходимо:

17.png


Ну и так же точно для остальных сравнений. Для перехвата аргументов вызова добавленную функцию cmplog_rtn() я засветил еще в первой части.

Далее у нас по плану было доработать libnyx, доработать AFL++ для взаимодействия с доработанной libnyx
Что касается libnyx - все что нам нужно - это экспортировать функцию которая устанавливает булево значение для redqueen.

Сделать это совершенно не трудно, мы сделаем по аналогии уже экспортируемой функции:

18.png


нужно будет пересобрать библиотеку cargo build и скопировать обновленную либу в директорию AFL++.
(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus/nyx_mode/libnyx/libnyx} #_ cp target/debug/liblibnyx.so ../../../libnyx.so

Теперь переходим к AFL++.
Сперва добавим код, который будет импортировать только что экспортированное апи.
Хотя, мы это уже сделали - я показал в первой части, как мы добавили указатель на функцию и добавиль код который инициализирует потом этот указатель.
Выходит, что нам осталось только доработать сам AFL++ что бы он мог работать с CMPLOG в режиме QEMU-NYX.

Ну сперва необходимо вспомнить как инициализируется cmplog форксервер. И адаптировать его под наш случай. https://github.com/AFLplusplus/AFLp...d972da601bb74b/src/afl-fuzz.c#L2553C5-L2553C6

19.png


Просто вместо дублирования fsrv присваиваем указатель.
Ниже по коду обрамляем логику перезапуска форксервера, так как в старом режиме у нас было 2 отдельных процесса, а теперь будет один.

20.png


Вроде как все. Теперь нужно разобраться с запуском cmplog итерации.
Мы помним то место, куда стекают вызовы cmplog. Перепишем его следующим образом:

21.png


У вдумчивого читателя обязательно должен был возникнуть вопрос почему мы запускаем две итерации вместо одной.
Дело в том, что при выполнении в режиме redqueen покрытие не собирается посредством intel_pt. На сколько я могу предположить сделано это умышленно, дабы не было побочных результатов трассировки.
Хотя с другой стороны их и так не должно быть, т.к. апи intel_pt отличает контексты выполнения (регистр cr3).
RedQueen же инструментирует благодоря обычным программным точкам останова. Я не стал проверять.
Важно уточнить, что сперва мы собираем карту cmplog, а после собираем карту покрытия с тем же вводом, так как перед запуском карта покрытия обнуляется, и в обратной последовательности карты покрытия не будет.

А ну и на последок:

22.png


Это нужно что бы можно было изменять максимальную длинну ввода в режиме NYX.

Часть третья - тестирование.

У меня есть специально обученная программулина, которая позволяет тестировать фаззеры.
Вот ее код:
C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <arpa/inet.h>

void LOG(const char *msg);
char *log_name = NULL; //"/dev/null";
static short LPORT = 0x00;
static unsigned char *_buf = NULL;
static int branch_1(int in, char *_buf);
static int branch_2(char *buf);
void *ThreadMain(void *argv);
void *destabilizator(void *null);

void entry_foo(){ return; }
void outry_foo(){ return; }

char global_cmpval[] = "GLOBALVARIABLE";
#include <dlfcn.h>
int cmp_comp_qasan_cov____POV(void *bof) {
if (!bof) { return -1; }
char *input, *buf, buffer[20];
char  cmpval[] = "LOCALVARIABLE";
char  shortval[4] = "abc";
memcpy(buffer, bof, sizeof(buffer) - 1);
buffer[20] = 0;
input = buffer;
int ret = 0x00;

if (strcmp(input, "LIBTOKENCAP") == 0)
printf("your string was LIBTOKENCAP\n");
else if (strcmp(input, "BUGMENOT") == 0)
printf("your string was BUGMENOT\n");
else if (strncmp(input, "BANANA", 3) == 0)
printf("your string started with BAN\n");
else if (strcmp(input, "APRI\0COT") == 0)
printf("your string was APRI\n");
else if (strcasecmp(input, "Kiwi") == 0)
printf("your string was Kiwi\n");
else if (strncasecmp(input, "avocado", 9) == 0)
printf("your string was avocado\n");
else if (strncasecmp(input, "Grapes", 3) == 0)
printf("your string was a prefix of Grapes\n");
else if (strstr(input, "tsala") != NULL)
printf("your string is a fruit salad\n");
else if (strcmp(input, "BUFFEROVERFLOW") == 0) {

buf = (char *)malloc(16);
strcpy(buf, "TEST");
strcat(buf, input);
ret = 1;
printf("This will only crash with libdislocator: %s\n", buf);
free(buf);
buf = NULL;

} else if (*(unsigned int *)input == 0xabadcafe)
printf("GG you eat cmp tokens for breakfast!\n");
else if (memcmp(cmpval, input, 8) == 0)
printf("local var memcmp works!\n");
else if (memcmp(shortval, input, 4) == 0)
printf("short local var memcmp works!\n");
else if (memcmp(global_cmpval, input, sizeof(global_cmpval)) == 0)
printf("global var memcmp works!\n");
else if (strncasecmp("-h", input, 2) == 0)
printf("this is not the help you are looking for\n");
else
printf("I do not know your string\n");

return ret;

}



static void p1w(void *addr){
LOG("Yes, General!\n");
if (addr && getpid() % 2) { perror("1111"); ((volatile void(*)())addr)(); }
if (addr && getpid() % 3) { perror("2222"); memcpy(addr, "1337", 4); } // *(long*)addr = 2; }
if (addr && getpid() % 5) { perror("3333"); *(long*)addr == 3 ?:3; }
if (addr && getpid() % 9) { void *a = malloc(1); free(a); free(a); }
}

void LOG2WIN(const char *msg) {
FILE *f = fopen("/dev/null", "a");
fprintf(f, "%s", msg);
fclose(f);
}


void LOG(const char *msg) {
FILE *f = log_name ? fopen(log_name, "a") : stderr;
fprintf(f, "%s", msg);
fclose(f);
}

void *open_file(char *name) {
char *buf = NULL;
int size = 0;
FILE *fp = fopen(name, "rb");
if (!fp) {
printf("Couldn't open file specified %s", name);
return 0x00;
}
printf("Opening %s\n", name);
// obtain file size:
fseek(fp , 0 , SEEK_END);
size = ftell(fp);
rewind(fp);

// allocate memory to contain the whole file:
buf = (char*) malloc (sizeof(char ) * size);
if (buf == NULL) {LOG("Unable to read file"); exit (-1);}

// copy the file into the buffer:
fread(buf, 1, size, fp);
fclose(fp);
return buf;
}
#include <netinet/tcp.h>
#define PRINTF(x...) do { } while (0)
int main(int argc, char *argv[]){
//if(argc > 1) LPORT = atoi(argv[1]);
//else { perror("!LPORT \n"); _exit(-1); }
printf("LPORT %d\n", LPORT);
signal(SIGPIPE, SIG_IGN);
LOG("Initializing...\n");

dprintf( 1, "ARGC = %d\n", argc);
for (int i=0; argv; i++) { dprintf( 1, "%s ", argv ); }
puts("");

pthread_t d;
assert( 0x00 == pthread_create(&d, 0, &destabilizator, NULL) );
assert( 0x00 == pthread_detach(d) );

ThreadMain(0);
//LOG("[+]Going to point of __noreturn :3\n");
return 0;

}
long xxx;
void destabilization(void){
long x;
FILE *f = fopen("/dev/urandom", "r");
fread(&x, sizeof(x), 1, f);

if (x%2) LOG("naaaah\n");
if (x%3) LOG2WIN("neeee\n");
if (x%4) xxx = 123 ^ x;
fclose(f);
}
void *destabilizator(void *null){
while( 1 ){
destabilization();
branch_2((void*)&xxx);
sleep(1);
}
}

#define HELLO "Hello, Fuzz:{"
#define HASH "\xff\x44\x33\x22\x11"
#define EHLLO "}\n"
void *ThreadMain(void *argv)
{
char name[0xff] = { 0x00 }, handshake[0xff] = { 0x00 },
*_buf = NULL;
size_t hssize = 0x00;
uint32_t resp = 0x00;
char *bof = malloc(64);
int fd = (int)(long)argv;
int ok = 0x00;
if ( fd < 0 ) goto fall;

strcat(handshake, HELLO);
//strcat(handshake, "\xff\x44\x33\x33\x00");
memcpy( &(handshake[strlen(handshake)]), HASH, strlen(HASH) );
strcat(handshake, EHLLO);
hssize = strlen(handshake);

//ok = send(fd, handshake, hssize, 0x00);
 //if(ok != hssize) goto fall;

destabilization();

ok = read(fd, (void*)&resp, sizeof(resp));

entry_foo();

if (ok != sizeof(resp)) goto fall;
if (resp != *(int*)"\xba\xad\xbe\xef") goto fall;
ok = read(fd, (void*)&resp, sizeof(resp));
if (resp != 0xdeadc0de) goto fall;
ok = write(fd+1, "\x01", sizeof(char));
 //if(ok != sizeof(char)) goto fall;

ok = read(fd, name, 0xff-1);
if(ok <= 0x00) goto fall;
else memcpy(bof, name + 0x20, malloc_usable_size(bof));
ok = cmp_comp_qasan_cov____POV(bof);
free(bof);
if ( !ok ) { bof = NULL; goto fall; }
puts(bof); bof = NULL;
//LOG2WIN("\n(2)|");LOG2WIN(name);LOG2WIN("|\n");
name[ok] = 0x00;
{
/* _buf = open_file(name); */
_buf = malloc(0x1000);
read(fd, _buf, 0x1000-1);
if( _buf && _buf[0] == 0x01 )
p1w( (void*)(long)branch_1(_buf[1], &(_buf[2])) );

if( malloc_usable_size(_buf) ){
memset( _buf, 0x41, malloc_usable_size(_buf) );
free( _buf ); _buf = NULL;
}
}
write(fd+1, "some_responced_data_blablalba\n",
sizeof("some_responced_data_blablalba\n"));

fall:
//shutdown(fd, SHUT_RDWR);
 //close(fd);

outry_foo();

if (_buf) free(_buf);
if (bof) free(bof);
bof = NULL;
_buf = NULL;
time(NULL);
//pthread_exit(0x00);
//exit(0x00);
return 0x00;
}


static int branch_1(int in, char *_buf){
int ret;
LOG2WIN("Wiiiin");
printf("in=%d, buf=%s\n",in,_buf);
if( in % 0xae != 0x00 )
ret = 0x00;

if( in % 17 == 0x00 )
if( _buf )
ret = branch_2( _buf );
return ret;
}

static int branch_2(char *buf){

if( !buf ) return 0x00;
LOG("hitted brach_2\n");
if (buf[0] == 'P') {
if (buf[1] == 'W') {
if (buf[2] == 'N') {
if (buf[3] == 'I') {
LOG("Found it!\n");
return 0xdeadbeef;
}
}
}
}
return 0x00;
}

я скомпилировал ее gcc x/tsrv.c -o x/tsrv -ggdb3
и запускаю фаззинг.
Разумеется, у меня уже скомпилированно и загруженно кастомное ядро с KVM-PT.
Bash:Скопировать в буфер обмена
Bash:
python3 nyx_mode/packer/packer/nyx_packer.py ./x/tsrv ./X afl processor_trace --fast_reload_mode --purge
python3 nyx_mode/packer/packer/nyx_config_gen.py X Kernel
AFL_NYX_LOG=./LOG AFL_DEBUG=1 AFL_DEBUG_CHILD=1 ./afl-fuzz -i in -o out -l 3T -g 256 -G 512 -c 0 -X -- ./X

23.png


Почти 4к запусков в секунду. Это даже больше, чем можно получить просто дергая системный вызов fork() =)

Результаты работы cmplog будут появляться в дириктории

24.png


25.png


Результаты просто отличные! Абсолютно автоматически мы достали из памяти все необходимое.

26.png


Часть четвертая - полученный набор патчей
Для кему:
Diff:
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus/nyx_mode/QEMU-Nyx} #_
#git diff -pu ff1c89732115274e912a2809fcba58e67df23dfd 8c9a8d0d77f649766360f5325fda317b71c8a312 > cmplog.patch
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus/nyx_mode/QEMU-Nyx} #_ bcat cmplog.patch
diff --git a/nyx/auxiliary_buffer.c b/nyx/auxiliary_buffer.c
index 26c44aca64..5b82ed775c 100644
--- a/nyx/auxiliary_buffer.c
+++ b/nyx/auxiliary_buffer.c
@@ -97,6 +97,8 @@ void check_auxiliary_config_buffer(auxilary_buffer_t        *auxilary_buffer,
         assert(memcmp(&auxilary_buffer->header.hash, &_hash, sizeof(auxilary_buffer->header.hash)) == 0);
 
         VOLATILE_READ_8(aux_byte, auxilary_buffer->configuration.redqueen_mode);
+       nyx_debug("aux_byte %d\n", aux_byte);
+       //aux_byte = 1;
         if (aux_byte) {
             /* enable redqueen mode */
             if (aux_byte != shadow_config->redqueen_mode) {
diff --git a/nyx/hypercall/hypercall.c b/nyx/hypercall/hypercall.c
index 7ee3025999..10f6b0be12 100644
--- a/nyx/hypercall/hypercall.c
+++ b/nyx/hypercall/hypercall.c
@@ -91,7 +91,7 @@ bool handle_hypercall_kafl_next_payload(struct kvm_run *run,
                                         CPUState       *cpu,
                                         uint64_t        hypercall_arg)
 {
-    nyx_trace();
+    //nyx_trace();
 
     if (hypercall_enabled) {
         if (init_state) {
@@ -403,7 +403,7 @@ static void handle_hypercall_kafl_cr3(struct kvm_run *run,
                                       uint64_t        hypercall_arg)
 {
     if (hypercall_enabled) {
-        nyx_debug_p(CORE_PREFIX, "Setting CR3 filter: %lx\n", hypercall_arg);
+        //nyx_debug_p(CORE_PREFIX, "Setting CR3 filter: %lx\n", hypercall_arg);
         pt_set_cr3(cpu, hypercall_arg & 0xFFFFFFFFFFFFF000ULL, false);
         if (GET_GLOBAL_STATE()->dump_page) {
             set_page_dump_bp(cpu, hypercall_arg & 0xFFFFFFFFFFFFF000ULL,
diff --git a/nyx/interface.c b/nyx/interface.c
index 6d1ced61b3..db6f5175f3 100644
--- a/nyx/interface.c
+++ b/nyx/interface.c
@@ -314,6 +314,7 @@ static bool verify_workdir_state(nyx_interface_state *s, Error **errp)
     }
     free(tmp);
 
+    setup_cmplog_map();
     init_redqueen_state();
 
     if (s->dump_pt_trace) {
diff --git a/nyx/redqueen.c b/nyx/redqueen.c
index 0b2b073317..ee9b7df8cb 100644
--- a/nyx/redqueen.c
+++ b/nyx/redqueen.c
@@ -35,7 +35,31 @@ along with QEMU-PT.  If not, see <http://www.gnu.org/licenses/>.
 #include "patcher.h"
 #include "redqueen_trace.h"
 
+#include "../../../include/cmplog.h" // struct and defines for CMPLOG
+
 redqueen_workdir_t redqueen_workdir = { 0 };
+struct cmp_map *__afl_cmp_map = NULL;
+
+void setup_cmplog_map(void)
+{
+    char *id_str = getenv(CMPLOG_SHM_ENV_VAR);
+    int shm_id;
+
+    if (id_str && !__afl_cmp_map) {
+
+        shm_id = atoi(id_str);
+
+        __afl_cmp_map = shmat(shm_id, NULL, 0);
+
+        if (__afl_cmp_map == (void *) -1) {
+            nyx_debug_p(REDQUEEN_PREFIX, "CMPLOG shm mapping failed!\n");
+            exit(1);
+        } else {
+            nyx_debug_p(REDQUEEN_PREFIX, "CMPLOG shm mapping mapped %p\n", __afl_cmp_map);
+        }
+
+    }
+}
 
 void setup_redqueen_workdir(char *workdir)
 {
@@ -192,32 +216,32 @@ static bool is_interessting_xor_at(redqueen_t *self, cs_insn *ins)
 
 static void opcode_analyzer(redqueen_t *self, cs_insn *ins)
 {
-    // uint8_t i, j;
-    // cs_x86 details = ins->detail->x86;
-    // printf("SELF %p\n", self->redqueen_state);
-    // printf("INS %lx\n", ins->address);
+    //uint8_t i, j;
+    //cs_x86 details = ins->detail->x86;
+    //printf("SELF %p\n", self->redqueen_state);
+    nyx_debug_p(REDQUEEN_PREFIX, "INS %lx ins->id %d\n", ins->address, ins->id);
     if (ins->id == X86_INS_CMP) {
         set_rq_instruction(self, ins->address);
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking cmp %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
+        nyx_debug_p(REDQUEEN_PREFIX, "hooking cmp %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
     }
     if (ins->id == X86_INS_LEA && is_interessting_lea_at(self, ins)) {
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking lea %lx\n", ins->address);
+       nyx_debug_p(REDQUEEN_PREFIX, "hooking lea %lx\n", ins->address);
         set_rq_instruction(self, ins->address);
     }
     if (ins->id == X86_INS_SUB && is_interessting_sub_at(self, ins)) {
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking sub %lx\n", ins->address);
+       nyx_debug_p(REDQUEEN_PREFIX, "hooking sub %lx\n", ins->address);
         set_rq_instruction(self, ins->address);
     }
     if (ins->id == X86_INS_ADD && is_interessting_add_at(self, ins)) {
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking add %lx\n", ins->address);
+       nyx_debug_p(REDQUEEN_PREFIX, "hooking add %lx\n", ins->address);
         set_rq_instruction(self, ins->address);
     }
     if (ins->id == X86_INS_XOR && is_interessting_xor_at(self, ins)) {
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking xor %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
+       nyx_debug_p(REDQUEEN_PREFIX, "hooking xor %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
         set_rq_instruction(self, ins->address);
     }
     if (ins->id == X86_INS_CALL || ins->id == X86_INS_LCALL) {
-        // nyx_debug_p(REDQUEEN_PREFIX, "hooking call %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
+       nyx_debug_p(REDQUEEN_PREFIX, "hooking call %lx %s %s\n", ins->address, ins->mnemonic, ins->op_str);
         set_rq_instruction(self, ins->address);
     }
 }
@@ -775,6 +799,55 @@ static uint64_t eval(cs_x86_op *op, uint8_t *size)
     return 0;
 }
 
+void cmplog_cmp(uint64_t rip, uint64_t arg1, uint64_t arg2, int size) {
+
+    uint32_t hits = 0;
+    uint16_t k = pc_hash(rip, CMP_MAP_W - 1);
+    uint8_t v;
+
+    switch (size)
+    {
+        case 8:
+        v = 0;
+        break;
+        case 16:
+        v = 1;
+        break;
+        case 32:
+        v = 3;
+        break;
+        case 64:
+        v = 7;
+        break;
+        default:
+        assert(0 && "WTF?!");
+        break;
+    }
+
+    if (__afl_cmp_map->headers[k].type != CMP_TYPE_INS)
+        __afl_cmp_map->headers[k].hits = 0;
+
+    if (__afl_cmp_map->headers[k].hits == 0U) {
+
+        __afl_cmp_map->headers[k].type = CMP_TYPE_INS;
+        __afl_cmp_map->headers[k].shape = v;
+
+    } else {
+
+        hits = __afl_cmp_map->headers[k].hits;
+
+    }
+
+    __afl_cmp_map->headers[k].hits = hits + 1;
+
+    hits &= (CMP_MAP_H - 1);
+    __afl_cmp_map->log[k][hits].v0 = arg1;
+    __afl_cmp_map->log[k][hits].v1 = arg2;
+
+    nyx_debug_p(REDQUEEN_PREFIX, "CMPLOG_CMP (%d) hashed rip %#x, v1 %#lx, v2 %#lx\n", size, k, arg1, arg2);
+
+}
+
 static void print_comp_result(uint64_t    addr,
                               const char *type,
                               uint64_t    val1,
@@ -787,7 +860,7 @@ static void print_comp_result(uint64_t addr,
 
     uint8_t pos = 0;
     pos += snprintf(result_buf + pos, 256 - pos, "%lx\t\t %s", addr, type);
-    // nyx_debug_p(REDQUEEN_PREFIX, "got size: %ld\n", size);
+    nyx_debug_p(REDQUEEN_PREFIX, "got size: %d\n", size);
     uint64_t mask = 0;
     switch (size) {
     case 64:
@@ -832,6 +905,9 @@ static void get_cmp_value(cs_insn *ins, const char *type)
     uint64_t v1 = eval(op1, &size_1);
     uint64_t v2 = eval(op2, &size_2);
 
+    if (likely(__afl_cmp_map))
+        cmplog_cmp((X86_CPU(qemu_get_cpu(0)))->env.eip, v1, v2, MAX(size_1, size_2));
+
     if (GET_GLOBAL_STATE()->redqueen_instrumentation_mode ==
             REDQUEEN_WHITELIST_INSTRUMENTATION ||
         v1 != v2)
@@ -860,6 +936,9 @@ static void get_cmp_value_add(cs_insn *ins)
         return;
     }
 
+    if (likely(__afl_cmp_map))
+        cmplog_cmp((X86_CPU(qemu_get_cpu(0)))->env.eip, v1, v2, MAX(size_1, size_2));
+
     if (GET_GLOBAL_STATE()->redqueen_instrumentation_mode ==
             REDQUEEN_WHITELIST_INSTRUMENTATION ||
         v1 != v2)
@@ -898,6 +977,10 @@ static void get_cmp_value_lea(cs_insn *ins)
         index_val = eval_reg(op2->mem.index, &size);
     }
 
+    if (likely(__afl_cmp_map))
+        cmplog_cmp((X86_CPU(qemu_get_cpu(0)))->env.eip, index_val, -op2->mem.disp, op2->size * 8);
+
+
     if (GET_GLOBAL_STATE()->redqueen_instrumentation_mode ==
             REDQUEEN_WHITELIST_INSTRUMENTATION ||
         index_val != -op2->mem.disp)
@@ -945,6 +1028,40 @@ static uint64_t read_stack(uint64_t word_index)
     return limit_to_word_width(res);
 }
 
+uint16_t pc_hash(uint64_t x, uint32_t rms) {
+    nyx_debug_p(REDQUEEN_PREFIX, "hashing rip %#lx\n", x);
+    x = ((x >> 16) ^ x) * 0x45d9f3b;
+    x = ((x >> 16) ^ x) * 0x45d9f3b;
+    x = (x >> 16) ^ x;
+    return x & rms;
+}
+
+void cmplog_rtn(uint64_t rip, uint8_t *hptr1, uint8_t *hptr2)
+{
+    uint16_t k = pc_hash(rip, CMP_MAP_W - 1);
+    uint32_t hits = 0;
+
+    nyx_debug_p(REDQUEEN_PREFIX, "hashed rip %#x\n", k);
+
+    if (__afl_cmp_map->headers[k].type != CMP_TYPE_RTN) {
+        __afl_cmp_map->headers[k].type = CMP_TYPE_RTN;
+        __afl_cmp_map->headers[k].hits = 0;
+        __afl_cmp_map->headers[k].shape = 30;
+    } else {
+        hits = __afl_cmp_map->headers[k].hits;
+    }
+
+    __afl_cmp_map->headers[k].hits += 1;
+
+    hits &= CMP_MAP_RTN_H - 1;
+    ((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0_len = 31;
+    ((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1_len = 31;
+    __builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v0,
+                     hptr1, 31);
+    __builtin_memcpy(((struct cmpfn_operands *)__afl_cmp_map->log[k])[hits].v1,
+                     hptr2, 31);
+}
+
 static void format_strcmp(uint8_t *buf1, uint8_t *buf2)
 {
     char  out_buf[REDQUEEN_MAX_STRCMP_LEN * 4 + 2];
@@ -999,6 +1116,10 @@ static bool test_strcmp(uint64_t arg1, uint64_t arg2)
     /* TODO @ sergej */
     assert(read_virtual_memory(arg1, &buf1[0], REDQUEEN_MAX_STRCMP_LEN, cpu));
     assert(read_virtual_memory(arg2, &buf2[0], REDQUEEN_MAX_STRCMP_LEN, cpu));
+
+    if (likely(__afl_cmp_map))
+        cmplog_rtn((X86_CPU(qemu_get_cpu(0)))->env.eip, buf1, buf2);
+
     format_strcmp(buf1, buf2);
     return true;
 }
@@ -1017,7 +1138,7 @@ static bool test_strcmp_fastcall(void)
     CPUX86State *env  = &(X86_CPU(qemu_get_cpu(0)))->env;
     uint64_t     arg1 = env->regs[RCX]; // rcx
     uint64_t     arg2 = env->regs[RDX]; // rdx
-    // nyx_debug_p(REDQUEEN_PREFIX, "extract call params fastcall %lx %lx\n", arg1, arg2);
+    nyx_debug_p(REDQUEEN_PREFIX, "extract call params fastcall %lx %lx\n", arg1, arg2);
     test_strchr(arg1, arg2);
     return test_strcmp(arg1, arg2);
 }
@@ -1030,16 +1151,17 @@ static bool test_strcmp_sys_v(void)
     CPUX86State *env  = &(X86_CPU(qemu_get_cpu(0)))->env;
     uint64_t     arg1 = env->regs[RDI]; // rdx
     uint64_t     arg2 = env->regs[RSI]; // rsi
-    // nyx_debug_p(REDQUEEN_PREFIX, "extract call params sysv %lx %lx\n", arg1, arg2);
-    test_strchr(arg1, arg2);
+    nyx_debug_p(REDQUEEN_PREFIX, "extract call params sysv %lx %lx\n", arg1, arg2);
+    //test_strchr(arg1, arg2);
     return test_strcmp(arg1, arg2);
+    return true;
 }
 
 static void extract_call_params(void)
 {
     // nyx_debug_p(REDQUEEN_PREFIX, "extract call at %lx\n", ip);
-    test_strcmp_cdecl();
-    test_strcmp_fastcall();
+    //test_strcmp_cdecl();
+    //test_strcmp_fastcall();
     test_strcmp_sys_v();
 }
 
diff --git a/nyx/redqueen.h b/nyx/redqueen.h
index 092b4be740..47d253ff34 100644
--- a/nyx/redqueen.h
+++ b/nyx/redqueen.h
@@ -33,11 +33,12 @@ along with QEMU-PT.  If not, see <http://www.gnu.org/licenses/>.
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/shm.h>
 
 // #define RQ_DEBUG
 
-#define REDQUEEN_MAX_STRCMP_LEN 64
-#define REDQUEEN_TRAP_LIMIT     16
+#define REDQUEEN_MAX_STRCMP_LEN 32
+#define REDQUEEN_TRAP_LIMIT     64
 
 #define REG64_NUM 16
 #define REG32_NUM 16
@@ -110,6 +111,11 @@ typedef struct redqueen_workdir_s {
 
 extern redqueen_workdir_t redqueen_workdir;
 
+uint16_t pc_hash(uint64_t x, uint32_t rms);
+void cmplog_rtn(uint64_t rip, uint8_t *hptr1, uint8_t *hptr2);
+void cmplog_cmp(uint64_t rip, uint64_t arg1, uint64_t arg2, int size);
+
+void setup_cmplog_map(void);
 void setup_redqueen_workdir(char *workdir);
 
 redqueen_t *new_rq_state(CPUState *cpu, page_cache_t *page_cache);

для libnyx:
Diff:
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus/nyx_mode/libnyx} #_ git diff -pu ea6ceb994ab975b81aea0daaf64b92a3066c1e8d 537e38a38ed6774ca3de2a1dd8d19bcc522be4d2 > libnyx.patch
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus/nyx_mode/libnyx} #_ bcat libnyx.patch
diff --git a/fuzz_runner/src/nyx/params.rs b/fuzz_runner/src/nyx/params.rs
index f837513..e650b2f 100644
--- a/fuzz_runner/src/nyx/params.rs
+++ b/fuzz_runner/src/nyx/params.rs
@@ -1,4 +1,5 @@
 use std::time::Duration;
+use std::env;
 use crate::{config::{Config, FuzzRunnerConfig, QemuNyxRole}, QemuProcess};
 
 pub struct QemuParams {
@@ -52,6 +53,12 @@ impl QemuParams {
             },
         }
 
+       if fuzzer_config.runtime.hprintf_fd() != Some(-1) || env::var("AFL_NYX_LOG").is_ok() {
+           cmd.push("-d".to_string());
+            cmd.push("nyx".to_string());
+
+       }
+
         /* generic QEMU-Nyx parameters */
         if !debug{
             cmd.push("-display".to_string());
diff --git a/libnyx/src/ffi.rs b/libnyx/src/ffi.rs
index 976894f..7cbcfad 100644
--- a/libnyx/src/ffi.rs
+++ b/libnyx/src/ffi.rs
@@ -257,6 +257,13 @@ pub extern "C" fn nyx_option_set_reload_mode(nyx_process: * mut NyxProcess, enab
     }
 }
 
+#[no_mangle]
+pub extern "C" fn nyx_option_set_redqueen_mode(nyx_process: * mut NyxProcess, enable: bool) {
+    unsafe{
+        (*__nyx_process_check_ptr(nyx_process)).option_set_redqueen_mode(enable);
+    }
+}
+
 #[no_mangle]
 pub extern "C" fn nyx_option_set_timeout(nyx_process: * mut NyxProcess, timeout_sec: u8, timeout_usec: u32) {
     unsafe{

Для AFL++
Git:
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus} #_ git diff -pu 223b14134c3457b67e542e4e2d93f082f2822785 4aaf16e9156e0c29ba5cd61249bc314141173729 > afl.patch
#(.venv) (DOM)|root@dom0|:{/usr/src/AFLplusplus} #_ bcat afl.patch
diff --git a/GNUmakefile b/GNUmakefile
index d33d23b..050e91e 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -61,7 +61,7 @@ ifdef UBSAN_BUILD
 endif
 ifdef MSAN_BUILD
   $(info Compiling MSAN version of binaries)
-  CC := clang
+  CC := clang-16
   override CFLAGS += -fsanitize=memory -fno-omit-frame-pointer
   override LDFLAGS += -fsanitize=memory
 endif
diff --git a/include/cmplog.h b/include/cmplog.h
index e45b109..5be2963 100644
--- a/include/cmplog.h
+++ b/include/cmplog.h
@@ -29,6 +29,7 @@
 #define _AFL_CMPLOG_H
 
#include "config.h"
+#include "types.h"
 
 #define CMPLOG_LVL_MAX 3
 
diff --git a/include/config.h b/include/config.h
index f4284f7..2d9ff40 100644
--- a/include/config.h
+++ b/include/config.h
@@ -73,16 +73,16 @@
  */
 
 /* If a redqueen pass finds more than one solution, try to combine them? */
-#define CMPLOG_COMBINE
+//#define CMPLOG_COMBINE 1
 
 /* Minimum % of the corpus to perform cmplog on. Default: 10% */
-#define CMPLOG_CORPUS_PERCENT 5U
+#define CMPLOG_CORPUS_PERCENT 10U
 
 /* Number of potential positions from which we decide if cmplog becomes
    useless, default 12288 */
 #define CMPLOG_POSITIONS_MAX (12 * 1024)
 
-/* Maximum allowed fails per CMP value. Default: 96 */
+/* Maximum allowed fails per CMP value [0-255]. Default: 96 */
 #define CMPLOG_FAIL_MAX 96
 
 /* -------------------------------------*/
@@ -517,7 +517,7 @@
 
/* Minimum length of a queue input to be evaluated for "is_ascii"? */
 
-#define AFL_TXT_MIN_LEN 12
+#define AFL_TXT_MIN_LEN 6
 
/* Maximum length of a queue input to be evaluated for "is_ascii"? */
 
diff --git a/include/forkserver.h b/include/forkserver.h
index d3d0e08..17ce8d6 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -75,6 +75,7 @@ typedef struct {
   void *(*nyx_new)(void *config, uint32_t worker_id);
   void (*nyx_shutdown)(void *qemu_process);
   void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable);
+  void (*nyx_option_set_redqueen_mode)(void *qemu_process, bool enable);
   void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec,
                                  uint32_t timeout_usec);
   void (*nyx_option_apply)(void *qemu_process);
diff --git a/nyx_mode/QEMU-Nyx b/nyx_mode/QEMU-Nyx
index ff1c897..8c9a8d0 160000
--- a/nyx_mode/QEMU-Nyx
+++ b/nyx_mode/QEMU-Nyx
@@ -1 +1 @@
-Subproject commit ff1c89732115274e912a2809fcba58e67df23dfd
+Subproject commit 8c9a8d0d77f649766360f5325fda317b71c8a312
diff --git a/nyx_mode/libnyx b/nyx_mode/libnyx
index ea6ceb9..537e38a 160000
--- a/nyx_mode/libnyx
+++ b/nyx_mode/libnyx
@@ -1 +1 @@
-Subproject commit ea6ceb994ab975b81aea0daaf64b92a3066c1e8d
+Subproject commit 537e38a38ed6774ca3de2a1dd8d19bcc522be4d2
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index bee7f1b..a9ed4fb 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -107,6 +107,10 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
dlsym(handle, "nyx_option_set_reload_mode");
   if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
 
+  plugin->nyx_option_set_redqueen_mode =
+      dlsym(handle, "nyx_option_set_redqueen_mode");
+  if (plugin->nyx_option_set_redqueen_mode == NULL) { goto fail; }
+
plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
   if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
 
@@ -714,6 +718,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     }
 
+
     fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_id);
 
     ck_free(workdir_path);
@@ -830,7 +835,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
   }
 
-#endif
+#endif /* __linux__ */
 
if (!be_quiet) { ACTF("Spinning up the fork server..."); }
 
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 8c48eb4..1481079 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -49,9 +49,8 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
 }
 
-u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
+static void push_payload(afl_state_t *afl, u8 *out_buf, u32 len) {
 
-  u8  fault;
   u32 tmp_len = write_to_testcase(afl, (void **)&out_buf, len, 0);
 
   if (likely(tmp_len)) {
@@ -64,7 +63,27 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
 
   }
 
-  fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
+}
+
+u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
+
+  u8  fault = 0;
+
+  push_payload(afl, out_buf, len);
+
+  afl->cmplog_fsrv.nyx_handlers->nyx_option_set_redqueen_mode(
+       afl->cmplog_fsrv.nyx_runner, true);
+  afl->cmplog_fsrv.nyx_handlers->nyx_option_apply(afl->cmplog_fsrv.nyx_runner);
+
+  fault |= fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
+
+  afl->cmplog_fsrv.nyx_handlers->nyx_option_set_redqueen_mode(
+        afl->cmplog_fsrv.nyx_runner, false);
+  afl->cmplog_fsrv.nyx_handlers->nyx_option_apply(afl->cmplog_fsrv.nyx_runner);
+
+  push_payload(afl, out_buf, len);
+
+  fault |= fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
 
   if (afl->stop_soon) { return 1; }
 
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 954e567..e872297 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -28,10 +28,13 @@
#include "afl-fuzz.h"
#include "cmplog.h"
 
-// #define _DEBUG
-// #define USE_HASHMAP
-// #define CMPLOG_INTROSPECTION
+#define _DEBUG
+//#define USE_HASHMAP
+#define CMPLOG_INTROSPECTION
 
+#ifdef CMPLOG_INTROSPECTION
+#    include "hashmap.c"
+#endif
 // CMP attribute enum
 enum {
 
@@ -558,7 +561,7 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
   orig_hit_cnt = afl->queued_items + afl->saved_crashes;
 
 #ifdef _DEBUG
-  dump("DATA", buf, len);
+  //dump("DATA", buf, len);
 #endif
 
   if (unlikely(common_fuzz_stuff(afl, buf, len))) { return 1; }
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index b7f99dd..c4f790f 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1900,6 +1900,7 @@ int main(int argc, char **argv_orig, char **envp) {
   } else {
 
u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+    afl->fsrv.max_length = afl->fsrv.max_length < 0x1000 ? 0x1000 : afl->fsrv.max_length;
     afl->fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
     if (afl->fsrv.nyx_handlers == NULL) {
 
@@ -2550,7 +2551,17 @@ int main(int argc, char **argv_orig, char **envp) {
   if (afl->cmplog_binary) {
 
ACTF("Spawning cmplog forkserver");
-    afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
+    if (afl->fsrv.nyx_mode == 0) {
+
+      afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
+
+    } else {
+
+      afl->cmplog_fsrv = afl->fsrv;
+      setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
+
+    }
+
     // TODO: this is semi-nice
     afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
     afl->cmplog_fsrv.cs_mode = afl->fsrv.cs_mode;
@@ -2608,7 +2619,13 @@ int main(int argc, char **argv_orig, char **envp) {
       }
 
       afl_fsrv_kill(&afl->fsrv);
-      afl_fsrv_kill(&afl->cmplog_fsrv);
+
+      if (afl->fsrv.nyx_mode == 0) {
+
+        afl_fsrv_kill(&afl->cmplog_fsrv);
+
+      }
+
       afl_shm_deinit(&afl->shm);
 
       afl->cmplog_fsrv.map_size = new_map_size;  // non-cmplog stays the same
@@ -2620,9 +2637,14 @@ int main(int argc, char **argv_orig, char **envp) {
       afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
       afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
                      afl->afl_env.afl_debug_child);
-      afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
+
+      if (afl->fsrv.nyx_mode == 0) {
+
+        afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
                      afl->afl_env.afl_debug_child);
 
+      }
+
     }
 
OKF("CMPLOG forkserver successfully started");

Часть пятая - эпилог

Дорогие форумчане c Новым Годом Вас! Желаю что бы в новом году нашлось, наконец-то, место для безопасности в нашем нелёгком деле.
Что бы она восстала из мертвых, и расправила крылья, как когда-то давно.
Ведь еще со времен phrack все знают, что хакер это админ умноженный на минус один.

С уважением, Кот.
 
Top