A nasty piece of software, resisting of analyzing, can crash itself by jumping to the address 0. And what can you do, if you can't find a function that it does? All you see in your debugger is EIP/RIP=0 and empty stack because ESP/RSP=(garbage), and there is nothing more that can help you. How distressing and frustrating is this.
There is a Pintool I wrote. It intercepts all 'CALL 0' and 'JMP 0' instructions and log their addresses. It uses excellent Intel Pin.
It can catch a code like:
int main() { typedef void func(void); func* f = (func*)0; f(); };
... using:
... VOID CALL_reg(ADDRINT ip, ADDRINT op, THREADID threadid) { PIN_GetLock(&lock, threadid+1); log_info (ip, "CALL", op); PIN_ReleaseLock(&lock); } VOID CALL_mem(ADDRINT ip, ADDRINT *op_addr, unsigned int op_size, THREADID threadid) { PIN_GetLock(&lock, threadid+1); ADDRINT op; PIN_SafeCopy(&op, op_addr, op_size); log_info (ip, "CALL", op); PIN_ReleaseLock(&lock); }; ... // this function executed only during startup, so no need to optimize anything here: VOID Instrument_all(INS ins, VOID* v) { // CALL reg // N.B.: this doesn't work: if ((INS_Mnemonic(ins) == "CALL") && (INS_OperandIsReg(ins, 0))) if (INS_IsCall(ins) && (INS_OperandIsReg(ins, 0))) { INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(CALL_reg), IARG_INST_PTR, IARG_REG_VALUE, REG(INS_OperandReg(ins, 0)), IARG_THREAD_ID, IARG_END); } // CALL mem if (INS_IsCall(ins) && INS_OperandIsMemory(ins, 0)) { INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(CALL_mem), IARG_INST_PTR, IARG_MEMORYREAD_EA, IARG_MEMORYREAD_SIZE, IARG_THREAD_ID, IARG_END); } ...
Dunno why, but (INS_Mnemonic(ins) == "CALL") doesn't working, while (INS_Mnemonic(ins) == "JMP") does.
All the files. Both Windows and Linux.
Couple of more useful Pintools are in my book, including building manual.
UPD: At reddit
Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.