uint32_t dasm_print_instruction(uint32_t eip, uint8_t *data, uint32_t size, char *str) { INSTRUCTION inst; // step 2: fetch instruction- uint32_t instrsize = get_instruction(&inst, data, MODE_32); if( instrsize == 0 ) { // printf("invalid instruction\n"); return 0; } str[81] = '\0'; memset(str, 0x20, 81); int i; for (i=0;i<instrsize;i++) { snprintf(str+i*2, 36-2*i, "%02X", data[i]); } memset(str+strlen(str), 0x20, 81-strlen(str)); // step 3: print it get_instruction_string(&inst, FORMAT_INTEL, 0, str+32, 31); return instrsize; }
int get_single_instruction(BYTE* bytes, char* str, size_t bufsize){ INSTRUCTION inst; int len = 0; len = get_instruction(&inst, bytes, MODE_32); get_instruction_string(&inst, FORMAT_ATT, 0, str, bufsize); return len; }
/** --------------------------------------------------------------------------- \brief calculate instruction length of Addr \param \return \code \endcode -----------------------------------------------------------------------------*/ int GetInstructionLength(BYTE* Addr) { #ifdef _USE_LIBDASM_LIB INSTRUCTION instr = {0}; int Len = get_instruction(&instr, Addr, MODE_32); // check illegal opcode if (0 == Len) { _ASSERTE(!"get_instruction"); return -1; } #ifdef _DEBUG char string[256] = {0}; get_instruction_string(&instr, FORMAT_INTEL, 0, string, sizeof(string)); _tprintf(TEXT("%s\n"), string); #endif return Len; #else DISASSEMBLER Disassembler; INSTRUCTION * Instruction = NULL; if (TRUE != InitDisassembler(&Disassembler, ARCH_X86)) { _ASSERTE(!"InitDisassembler"); return -1; } ULONG Flags = DISASM_DISASSEMBLE | DISASM_DECODE | DISASM_STOPONERROR | DISASM_STOPONANOMALY | DISASM_STOPONRETURN; Instruction = GetInstruction(&Disassembler, (ULONG)Addr, (PBYTE)Addr, Flags); if (!Instruction) { _ASSERTE(!"GetInstruction"); CloseDisassembler(&Disassembler); return -1; } #ifdef _DEBUG DumpInstruction(Instruction, TRUE, TRUE); #endif int Len = Instruction->Length; CloseDisassembler(&Disassembler); return Len; #endif//_USE_LIBDASM_LIB }
void runPlugin(static HANDLE hProcess, PUNRESOLVED_IMPORT unresolvedImport, unsigned int eip){ DWORD_PTR invalidApiAddress = 0; INSTRUCTION inst; int max_instruction_size = sizeof(UINT8)*15; LPVOID instruction_buffer = (LPVOID)malloc(max_instruction_size); int instruction_size; char buffer[200]; while (unresolvedImport->ImportTableAddressPointer != 0){ //last element is a nulled struct printf("Unresolved : 0x%08x\n", unresolvedImport->InvalidApiAddress); invalidApiAddress = unresolvedImport->InvalidApiAddress; readMemoryFromProcess(hProcess, invalidApiAddress, max_instruction_size, instruction_buffer); instruction_size = get_instruction(&inst, (BYTE *)instruction_buffer, MODE_32); get_instruction_string(&inst, FORMAT_ATT, 0, buffer, sizeof(buffer)); printf("INS: %s\n",buffer); if(inst.type == INSTRUCTION_TYPE_PUSH){ //pushl $0x770fdfa4 char *pch = strstr (buffer,"0x"); //printf("ADDRESS: %s\n",pch); unsigned int correct_address = (unsigned int)strtoul(pch,NULL,16); printf("ADDRESS: %08x\n",correct_address); bool res = writeMemoryToProcess(hProcess, (DWORD_PTR)(unresolvedImport->ImportTableAddressPointer), sizeof(correct_address), &correct_address); printf("writeMemoryToProcess result %d\n" , res); }else{ if(inst.type == INSTRUCTION_TYPE_JMP){ // jmp 0x73d3673d //printf("ADDRESS: %s\n",pch); unsigned int correct_address = ( (unsigned int)strtoul(strstr(buffer, "jmp") + 4 + 2, NULL, 16)) + invalidApiAddress; //printf("ADDRESS: %08x\n",correct_address); bool res = writeMemoryToProcess(hProcess, (DWORD_PTR)(unresolvedImport->ImportTableAddressPointer), sizeof(correct_address), &correct_address); //printf("writeMemoryToProcess result %d\n" , res); } } //if libdasm fails to recognize the insruction bypass this instruction if(instruction_size == 0){ invalidApiAddress = invalidApiAddress + 1; continue; } unresolvedImport++; //next pointer to struct } }
////////////////////////////////////////////////////////////////////////// // CPU运行,是一个循环 int CPURun() { WORD cs=-1; while (1) { if (debugHelp==1&&OutDisam==1 && (eCPU.cs==cs || cs==(WORD)-1)){ get_instruction(&inst, (BYTE *)evIP + MemoryStart, MODE_16); get_instruction_string(&inst, FORMAT_INTEL, 0, szCode, 300); fprintf(fp, "%4x:%4x : %s\n", eCPU.cs, eCPU.ip, szCode); fflush(fp); cs = eCPU.cs; } //MessageBox(NULL, szCode, NULL, NULL); debugHelp = 1; ExecIns(); FlashRAM(); ExecInt(); #ifdef _VM_DEBUG_ if (eCPU.ip==0xa6ba && eCPU.cs==0x1cd) { __asm nop //这里方便自己调试程序 } if (eCPU.ip==0x169 && eCPU.cs==0x8a00) { __asm nop //这里方便自己调试程序 } if (eCPU.ip==0x3d7 && eCPU.cs==0x1e10) { __asm nop //这里方便自己调试程序 } #endif } return 0; }
int main(int argc, char **argv) { INSTRUCTION inst; // declare struct INSTRUCTION unsigned char *data; int i, c = 0, bytes, format = FORMAT_INTEL, mode = MODE_32, size, len; char string[256]; if (argc < 2) { printf("\nSimple x86 disassembler example\n"); printf("Compiled with libdasm %d.%d.%d.%d\n\n", LIBDASM_VERSION_MAJOR, LIBDASM_VERSION_MINOR1, LIBDASM_VERSION_MINOR2, LIBDASM_VERSION_MINOR3); printf("Usage: %s <file> [-a|-i] [bytes]\n" " file file to be disassembled (required)\n" " -a format: ATT (optional)\n" " -i format: INTEL (optional, default)\n" " bytes show raw instruction data (optional, default 8)\n\n", argv[0]); exit (1); } data = read_file(&size, argv[1]); bytes = 8; if (argc > 2) { if (argv[2][0] == '-') { switch(argv[2][1]) { case 'a': format = FORMAT_ATT; break; case 'i': format = FORMAT_INTEL; break; } if (argc > 3) { bytes = atoi(argv[3]); } } else { bytes = atoi(argv[2]); } } signal(SIGSEGV, sighandler); while (c < size) { /* * get_instruction() has the following parameters: * * - &inst is a pointer to struct INSTRUCTION * - data + c is pointer to data to be disassembled * - disassemble in 32-bit mode: MODE_32 */ len = get_instruction(&inst, data + c, mode); // Illegal opcode or opcode longer than remaining buffer if (!len || (len + c > size)) { printf("%.8x ", c); if (bytes) { printf("%.2x ", data[c]); for (i = 1; i < bytes*2 - 1; i++) { printf(" "); } } if (format == FORMAT_INTEL) { printf("db 0x%.2x\n", *(data + c)); } else { printf(".byte 0x%.2x\n", *(data + c)); } c++; continue; } /* * Print absolute offset and raw data bytes up to 'bytes' * (not needed, but looks nice). * */ printf("%.8x ", c); if (bytes) { for (i = 0; i < MIN(bytes, len); i++) { printf("%.2x", data[c + i]); } printf(" "); for (i = MIN(bytes, len); i < bytes*2 - len; i++) { printf(" "); } } /* * Print the parsed instruction, format using user-supplied * format. We could of course format the instruction in some * other way by accessing struct INSTRUCTION members directly. */ get_instruction_string(&inst, format, (DWORD)c, string, sizeof(string)); printf("%s\n", string); c += len; } return 0; }
// Entry point of the plugin // This function will be called PINdemonium void runPlugin(static HANDLE hProcess, PUNRESOLVED_IMPORT unresolvedImport, unsigned int eip){ //local variable int max_instruction_size = sizeof(UINT8)*15; int insDelta; char buffer[2048]; int j,instruction_size; INSTRUCTION inst; DWORD_PTR invalidApiAddress = 0; MEMORY_BASIC_INFORMATION memBasic = {0}; LPVOID instruction_buffer = (LPVOID)malloc(max_instruction_size); while (unresolvedImport->ImportTableAddressPointer != 0) //last element is a nulled struct { bool resolved = false; insDelta = 0; invalidApiAddress = unresolvedImport->InvalidApiAddress; //get the starting IAT address to be analyzed yet for (j = 0; j < 1000; j++) { //if we cannot query the invalidApiAddress then bypass the analysis of this address SIZE_T result = VirtualQueryEx(hProcess,(LPVOID)invalidApiAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)); if (!result || memBasic.State != MEM_COMMIT || memBasic.Protect == PAGE_NOACCESS) { //if the memory region pointed by invalidApiAddress isn't mapped break the for loop and check the next unresolved import break; } //read the memory pointed by invalidApiAddress of the external process in order to disassembke the first instruction found //we read 15 bytes because in the x86varchitectures the instructions are guaranteed to fit in 15 bytes readMemoryFromProcess(hProcess, invalidApiAddress, max_instruction_size, instruction_buffer); //disassemble the first instruction in the buffer //instruction_size will contains the length of the disassembled instruction (0 if fails) instruction_size = get_instruction(&inst, (BYTE *)instruction_buffer, MODE_32); //if libdasm fails to recognize the insruction bypass this instruction if(instruction_size == 0){ invalidApiAddress = invalidApiAddress + 1; insDelta = insDelta + 1; continue; } get_instruction_string(&inst, FORMAT_ATT, 0, buffer, sizeof(buffer)); //check if it is a jump if (strstr(buffer, "jmp")) { //calculate the correct answer (add the invalidApiAddress to the destination of the jmp because it is a short jump) unsigned int correct_address = ( (unsigned int)std::strtoul(strstr(buffer, "jmp") + 4 + 2, NULL, 16)) + invalidApiAddress; /* printf("\n\n---------------- MINI REP --------------\n"); printf("INST %s: \n", buffer); printf("INVALID API : %08x \n", invalidApiAddress); printf("INST DELTA %d \n", insDelta); printf("IAT POINTER : %p\n", unresolvedImport->ImportTableAddressPointer); printf("CORRECT ADDR : %08x\n", correct_address); //printf("SIZE OF CORRECT ADDR: %d\n", sizeof(correct_address)); printf("---------------- END MINI REP --------------\n\n"); */ //if the target address is in a memory space dedicated to dlls we have finished our check if(correct_address >= 0x50000000 && correct_address <= 0x7f000000){ //subtract the stolen API executed correct_address = correct_address - insDelta; writeMemoryToProcess(hProcess, (DWORD_PTR)(unresolvedImport->ImportTableAddressPointer), sizeof(correct_address), &correct_address); //unresolved import probably resolved resolved = true; break; } //follow the target address of the jmp and continue the search //we don't have to increase the INSDelta beccause the jmp itself is not a stolen API (instruction belonging to the dll) else{ invalidApiAddress = correct_address; continue; } } //if not increment the delta for the next fix (es : if we have encountered 4 instruction before the correct jmp we have to decrement the correct_address by 16 byte) insDelta = insDelta + instruction_size; //check the next row inthe IAT invalidApiAddress = invalidApiAddress + instruction_size; } /* //if we cannot resolve the import fix it with a dummy address so scylla isn't able to resolve the API and it will remove the unresolved import // this functionality is optional (set the flag nullify_unknown_iat_entry_flag as true with command line) because it can break the program if(!resolved){ unsigned int correct_address = 0x0; writeMemoryToProcess(hProcess, (DWORD_PTR)(unresolvedImport->ImportTableAddressPointer), sizeof(correct_address), &correct_address); resolved = false; } */ unresolvedImport++; //next pointer to struct } }
static DWORD WINAPI debug_A(LPVOID lpParam) { para *a = (para *)lpParam; CONTEXT thread_context; bool key_execption; DEBUG_EVENT debugevent; FILE *ERRORfile=fopen("ERROELOG.TXT", "a+"); HANDLE openthread; HANDLE openprocess; int exception_key=0; INSTRUCTION inst; char *memery_context = (char*)malloc(sizeof(char)); char *memory_context = (char*)malloc(sizeof(char)); //************************************************************************************************************************************** bool debug_creat_init = DebugActiveProcess(a->pi.dwProcessId); if(!debug_creat_init) { printf("[*]调试器附加失败!错误代码:%d 请检查系统状况!\n",GetLastError()); fprintf(ERRORfile, "调试器附加失败,请检查系统状况!\n"); getchar(); fprintf(ERRORfile,"====================================================================================================调试结束\n"); return 0; } printf("[!]调试器附加成功!开始进行调试循环\n"); while(GetTickCount()-a->start_time<=a->wait_time) { if(WaitForDebugEvent(&debugevent,1000))//INFINITE一直等待调试事件的发生 { if(debugevent.dwDebugEventCode!=EXCEPTION_DEBUG_EVENT)//不是调试异常事件 { ContinueDebugEvent(debugevent.dwProcessId,debugevent.dwThreadId,DBG_CONTINUE);//释放所有的线程 continue; } if((openthread =OpenThread(THREAD_ALL_ACCESS,FALSE,debugevent.dwThreadId))==NULL) { printf("附加进程出错,错误代码:%d",GetLastError()); fprintf(ERRORfile, "附加进程出错,错误代码:%d",GetLastError()); getchar(); fprintf(ERRORfile,"====================================================================================================调试结束\n"); return 0; } thread_context.ContextFlags=CONTEXT_FULL; if(GetThreadContext(openthread,&thread_context)==0) { printf("获取进程信息失败! 错误代码:%d\n",GetLastError()); fprintf(ERRORfile, "获取进程信息失败!\n"); getchar(); fprintf(ERRORfile,"====================================================================================================调试结束\n"); return 0; } switch (debugevent.u.Exception.ExceptionRecord.ExceptionCode) { case CREATE_THREAD_DEBUG_EVENT: printf("[*]调试开始,调试事件CREATE_THREAD_DEBUG_EVENT\n"); break; case EXCEPTION_ACCESS_VIOLATION: key_execption=true; printf("[!]软件错误!非法访问(EXCEPTION_ACCESS_VIOLATION)!\n"); fprintf(ERRORfile, "[*]软件错误!非法访问(EXCEPTION_ACCESS_VIOLATION)!\n"); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: key_execption=true; printf("[!]软件错误!原因EXCEPTION_INT_DIVIDE_BY_ZERO"); fprintf(ERRORfile, "[*]软件错误!原因EXCEPTION_INT_DIVIDE_BY_ZERO"); break; case EXCEPTION_STACK_OVERFLOW: key_execption=true; printf("[!]软件错误!原因EXCEPTION_STACK_OVERFLOW"); fprintf(ERRORfile, "[*]软件错误!原因EXCEPTION_STACK_OVERFLOW"); case EXIT_PROCESS_DEBUG_EVENT: printf("[!]软件退出调试器!\n"); break; default: key_execption=FALSE; ContinueDebugEvent(debugevent.dwProcessId,debugevent.dwThreadId,DBG_CONTINUE); } if(key_execption)//异常逆向 { exception_key++; if((openprocess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,debugevent.dwProcessId))==NULL) { printf("[!]错误!进程附加失败!\n"); fprintf(ERRORfile, "[!]错误!进程附加失败!\n"); return -1; } ReadProcessMemory(openprocess,(void*)thread_context.Eip,memery_context,32,NULL); printf("*******************************************************************************\n"); get_instruction(&inst,(BYTE *)memery_context,MODE_32); get_instruction_string(&inst,FORMAT_INTEL,0,memory_context,64); printf("[*]发现异常\n CPU: EIP [%x] EAX [%x] EBX [%x] ECX [%x] EDX [%x]\n ",thread_context.Eip,thread_context.Eax,thread_context.Ebx,thread_context.Ecx,thread_context.Edx); printf("[*]ESI [%x] EDI [%x] EBP [%x]\n",thread_context.Esi,thread_context.Edi,thread_context.Ebp); printf("[*]异常内存 %x",memery_context); fprintf(ERRORfile,"[*]发现异常\n CPU: EIP [%x] EAX [%x] EBX [%x] ECX [%x] EDX [%x]\n ",thread_context.Eip,thread_context.Eax,thread_context.Ebx,thread_context.Ecx,thread_context.Edx); fprintf(ERRORfile,"[*]ESI [%x] EDI [%x] EBP [%x]\n",thread_context.Esi,thread_context.Edi,thread_context.Ebp); fprintf(ERRORfile,"[*]异常内存 %x",memery_context); key_execption=FALSE; printf("[*]异常分析完成!\n"); printf("*******************************************************************************\n"); } ContinueDebugEvent(debugevent.dwProcessId,debugevent.dwThreadId,DBG_CONTINUE); printf("剩余调试时间: %d",GetTickCount()-a->start_time); } } printf("[*]进程 调试完成,花费时间:%dms,发现异常数目为:%d\n",a->wait_time,exception_key); printf("[*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*]\n"); fprintf(ERRORfile,"[*]进程 调试完成,花费时间:%dms,发现异常数目为:%d\n",a->wait_time,exception_key); fprintf(ERRORfile,"[*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*]\n"); return 0; }