Долго но плохо искал, нашел SoftX86 на sourceforg.net, очень понравилось но ксожалению только для 16 битного кода. Можно ли использовать мутантов типа boch, или wine для этих целей, тоесть втроить в программц как модуль или есть какие другие средства? Мне вполне достаточно будет вычислять несложные выражения и проверять константность условий. Код (Text): mov eax,1 mov ecx,2 add eax,ecx Код (Text): xor eax,eax jz true Если для этих целей использовать дизассемблер то там придется как-то отслеживать, даже с информацией об операндах и флагах(как в xde/disit), будет сложновато.
если эмулировать только регистры и флажки, то вообщем-то ничего сложного -- на каждый регистр заводишь переменную-значение и переменную-тэг. 'Значение' хранит (как ни странно) текущее значение регистра. Тэг показывает состояние эмулируемого регистра -- в простейшем случае флажок константа/неконстанта. Аналогично для eflags. Когда встречаешь команду загрузки/обнуления/etc. imm-значения в регистр, помечаешь тэг регистра как константу и запоминаешь значение регистра. Далее... 1) встретив команду, все операнды которой 'известны', выполняешь ее над запомненнными значениями регистров, результат помечаешь как константу, флажки помечаешь как известные, pushf/pop в значение eflags. 2) если хотя бы один операнд 'неизвестен' (например, операнд из памяти, если память не эмулится), помечаешь результат как unknown (и флажки, если надо). Такое может например понадобится для обнаружения заведомо срабатывающих/несрабатывающих условных переходов -- типа Код (Text): mov eax, 1243254543h xor eax, 432535354h add eax, 53453463h sub eax, 23424534h cmp eax, 345434554h jc somewhere и для твоего случая тоже должно по идее подойти.
_BC_ Ну раз ничего сложного, будем пробовать IceStudent Видел, разве удастся отделить их от иды и заюзать?
Вот эмулятор www.droopy.narod.ru/download/lezgin.htm Правда он кривой немного и исходники все потерялись. Но я работаю над этим
Что делать не знаю. Говорю исходников нет. Я сам его уже 2 недели дизассемблирую. А что именно за задача стоит? Можно написать что-нибудь похожее. Это не так уж сложно
droopy Вообще идеальная ситуация, задать состояние проца структурой Код (Text): struct Context { DWORD ip struct Register { bool undefined; // не инициализирован DWORD value; } Register regs[8]; bool (*om_memory_read)(DWORD address, DWORD size); bool (*om_memory_write)(DWORD address, DWORD size); } bool execute(Context* context, byte* code, int length); Я устанавливаю контекст, колбеки на чтение запись, и пробую исполнить кусок кода,(мжно даже пошагово) получаю результат или болт А задача, ну вычислить статическое выражение или проверить условие перехода, там выше написано, тоесть полная эмуляция мне не нужна
А если подумать то и условия проверять не нужно. Ну кратко вообщем расскажу Код (Text): #pragma comment(linker,"/ENTRY:main") extern "C" { char* strcpy(char*,char*); int printf(char*,...); } int main(int argc, char** argv) { char buffer[10]; char program[10]; for(int i=0; i<argc; i++) { if(i==0) { strcpy(buffer,argv[i]); } else if(i==1) { strcpy(buffer,argv[i]); } else { return 0; } } printf("%s %s\n",program,buffer); return 1; } Код (Text): 00401000> sub_00401000-0 00401000: SUB ESP,1CH 00401003: MOV EAX,[0040A000H] 00401008: XOR EAX,ESP 0040100A: MOV [ESP+18H],EAX 0040100E: PUSH EBX 0040100F: MOV EBX,[ESP+24H] 00401013: PUSH ESI 00401014: XOR ESI,ESI 00401016: TEST EBX,EBX 00401018: PUSH EDI 00401019: JLE L_00401063 0040101B: MOV EDI,[ESP+30H] 0040101F: NOP L_00401020: 00401020: TEST ESI,ESI ;+00401061 00401022: JNZ L_0040103E 00401024: MOV EAX,[EDI] 00401026: LEA EDX,[ESP+0CH] 0040102A: SUB EDX,EAX 0040102C: LEA ESP,[ESP] L_00401030: 00401030: MOV CL,[EAX] ;+0040103A 00401032: MOV [EDX+EAX],CL 00401035: ADD EAX,01H 00401038: TEST CL,CL 0040103A: JNZ L_00401030 0040103C: JMP L_0040105C L_0040103E: 0040103E: CMP ESI,01H ;-00401022 00401041: JNZ L_00401091 00401043: MOV EAX,[EDI+04H] 00401046: LEA EDX,[ESP+0CH] 0040104A: SUB EDX,EAX 0040104C: LEA ESP,[ESP] L_00401050: 00401050: MOV CL,[EAX] ;+0040105A 00401052: MOV [EDX+EAX],CL 00401055: ADD EAX,01H 00401058: TEST CL,CL 0040105A: JNZ L_00401050 L_0040105C: 0040105C: ADD ESI,01H ;-0040103C 0040105F: CMP ESI,EBX 00401061: JL L_00401020 L_00401063: 00401063: LEA EAX,[ESP+0CH] ;-00401019 00401067: PUSH EAX 00401068: LEA ECX,[ESP+1CH] 0040106C: PUSH ECX 0040106D: PUSH 00408108H 00401072: CALL sub_004010A5 00401077: ADD ESP,0CH 0040107A: POP EDI 0040107B: POP ESI 0040107C: MOV EAX,00000001H 00401081: POP EBX 00401082: MOV ECX,[ESP+18H] 00401086: XOR ECX,ESP 00401088: CALL sub_0040116A 0040108D: ADD ESP,1CH 00401090: RET L_00401091: 00401091: MOV ECX,[ESP+24H] ;-00401041 00401095: POP EDI 00401096: POP ESI 00401097: POP EBX 00401098: XOR ECX,ESP 0040109A: XOR EAX,EAX 0040109C: CALL sub_0040116A 004010A1: ADD ESP,1CH 004010A4: RET В атаче рисунок, это типа граф переходов который я получаю после, анализа кода <С> условие, (J) прижок, поток инструкции, {T} завершающая инструкция. Теперь, нулевой блок представляет из себя, условие тоесть <C> и состоит из инструкций Код (Text): 00401000: SUB ESP,1CH 00401003: MOV EAX,[0040A000H] 00401008: XOR EAX,ESP 0040100A: MOV [ESP+18H],EAX 0040100E: PUSH EBX 0040100F: MOV EBX,[ESP+24H] 00401013: PUSH ESI 00401014: XOR ESI,ESI 00401016: TEST EBX,EBX 00401018: PUSH EDI 00401019: JLE L_00401063 Но насамом деле условие это Код (Text): 0040100F: MOV EBX,[ESP+24H] 00401013: PUSH ESI 00401014: XOR ESI,ESI 00401016: TEST EBX,EBX 00401018: PUSH EDI 00401019: JLE L_00401063 И если это проэмулировать получится, более ясная картина, пролого функции -> <C> вместо <C> Также и с конструкциями типа IF, можно будет отделить, инструкции не относящиеся к вычислению перехода, например: Код (Text): bool calc=true; x = 1,y = 2; if(calc) { } Здесь получится определить что операции над "x = 1,y = 2;" не относятся к условию "if(calc)", и чем больше таких ситуаций распознается тем меньша нужно вмешательство интелекта в ход разбора А вот что с этим всем делать уже другая история
хм, процедуры с алгоритмами, которые зависят от внешних (по отношению к процедуре) аргументов и переменных -- это совсем не статическое выражение, которое можно 'вычислить' эмулятором. Если уж тут что эмулировать, то только 'символьно'.
_BC_ Ну значит мне нужно "символьно", низнаю как это но мне наверное подходит Смысл в чем, если можно получить дополнительную инфу через выполнение нескольких инструкций это хорошо, если выполнение невозможно, ну и без него справимся. Кароче, дело к ночи, толку нету, помогу себе сам.
Нет, всетаки процесс пошел, я зря парил вам мозг, технологии предложеной товарищем _BC_, мне вполне хвати, просто рашитывал получить все и сразу
имхо лучше бы сказал, какая конечная задача. Что-то мне подсказывает, что размышления вида "а вот мы выполним эти несколько команд, а затем по изменениям регистров/флагов/и тп сделаем выводы" едва ли помогут в ее решении, анализ кода и эмуляция -- вещи разные.
нда, было что-то такое, но оно выдавало сишный код, который читался куда хуже своей ассемблерной первообразной.
Rec 2.0 даёт довольно неплохие результаты, особенно когда надо какой-нибудь крипто/математический алгоритм зареверсить.
Мой алгоритм эмуляции выглядит примерно так: Код (Text): call GetNextByte ;читает al <-[eip] and eax, 0FFh call dword ptr emul_table[eax*4] ..... emul_add_rmb: call GetNextByte call GetByteOperands ;возвращает в ebx и ecx указатели на операнды команды ;это может быть память или регистр (Reg...) mov al, [ecx] add [ebx], al pushfd pop RegFlags ret ... .data RegEax dd 0 RegEbx dd 0 RegEcx dd 0 RegEdx dd 0 RegEsi dd 0 RegEdi dd 0 RegEbp dd 0 RegEsp dd 0 RegEip dd 0 RegFlags dd 0 emul_table label dword dd offset emul_add_rmb dd offset emul_add_rmd ... Вот и все, по-моему, ничего сложного. Вооружаешься справочником по командам x86 и забиваешь всю таблицу.