This is a rudimentary runtracer for Windows 7 on x86 (ASLR resilient).
0c338f0abacb1298c6e3159ef4e1383419cd701b04ef15d5434f37c70994813a
// Blocks the c version
// http://nsense.net
// Joakim "JODE" Sandström
//
// Description: Dumb runtracing. Sorry about the messy code - it reflects the inside of my head.
// Platform: Win7 x86
//
#include <windows.h>
#include <Dbghelp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <psapi.h>
#include <time.h>
#include <map>
#include <string>
#include <set>
#include "distorm.h"
using namespace std;
#pragma comment(lib, "distorm.lib")
//#define VERBOSE "on" // enable to get debug outputs.
#define showUsage() printf("-[Blocks by nSense 2011\n Usage: blocks.exe -f filename -p param -o output -w delay")
typedef struct _ModuleInfo {
char FileName[MAX_PATH];
long lBase;
long lCodeMaxAddress;
bool bDll;
long lSizeOfCode;
unsigned char* PCodeCache;
} *PModuleInfo;
// The number of the array of instructions the decoder function will use to return the disassembled instructions.
// Play with this value for performance...
#define MAX_INSTRUCTIONS (100)
#define BUFSIZE 512
DWORD dwContinueStatus = DBG_CONTINUE;
std::map<LPVOID, std::string> DllNameMap;
std::map<long, unsigned int> OrginalBytesCache;
std::map<long, _DInst> BranchingDynamicRegister;
std::map<long, long> BackFlowLocation;
set<long>BackFlowOffset;
set<long>AnalyzedBreakPoints;
set<long>KnownBreakPoints;
set<long>AnalyzedOffsets;
set<long>BranchingDynamicBreakPoint;
set<long>VisitedBreakPoints;
IMAGE_NT_HEADERS I_NT;
HMODULE *hmodules = 0;
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO StartupInfo;
bool bContinueDebugging = true;
bool HasAnalyzedEntryPoint = false;
char OutputFileName[MAX_PATH];
long ModuleCount = 0;
int TimeOut;
PModuleInfo tracedmodules = new _ModuleInfo[MAX_PATH];
void EnableDebugPriv() {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken );
LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid );
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = luid;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges( hToken, false, &tkp, sizeof( tkp ), NULL, NULL );
CloseHandle( hToken );
}
char* GetFileNameFromHandle(HANDLE hFile)
{
BOOL bSuccess = FALSE;
TCHAR pszFilename[MAX_PATH+1];
HANDLE hFileMap;
char strFilename[MAX_PATH];
memset(strFilename,NULL, sizeof(strFilename));
// Get the file size.
DWORD dwFileSizeHi = 0;
DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
return FALSE;
// Create a file mapping object.
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0,
1,
NULL);
if (hFileMap)
{
// Create a file mapping to get the file name.
void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
if (pMem)
{
if (GetMappedFileName(GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
// Translate path with device name to drive letters.
TCHAR szTemp[BUFSIZE];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(BUFSIZE-1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
BOOL bFound = FALSE;
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = strlen(szName);
if (uNameLen < MAX_PATH)
{
bFound = strncmp(pszFilename, szName, uNameLen) == 0;
if (bFound)
sprintf(strFilename,"%s%s",szDrive, pszFilename+uNameLen);
}
}
while (*p++);
} while (!bFound && *p); // end of string
}
}
bSuccess = TRUE;
UnmapViewOfFile(pMem);
}
CloseHandle(hFileMap);
}
return(strFilename);
}
bool InScope(unsigned long absolute_target_address){
// notice the isdll (can be used to limit depth - in future)
for(int ii = 0;ii<ModuleCount;ii++){
if(tracedmodules[ii].lBase < absolute_target_address && absolute_target_address < tracedmodules[ii].lCodeMaxAddress && tracedmodules[ii].bDll == false)
return true;
}
#ifdef VERBOSE
printf("Inscope: not in scope: %x\n", abosulte_target_address);
#endif
return false;
}
void RemoveBreakPoint(long absoluteoffset, DWORD dwThreadId)
{
unsigned int obyte= OrginalBytesCache[(long)absoluteoffset];
CONTEXT ctx;
HANDLE th = OpenThread(THREAD_ALL_ACCESS, NULL, dwThreadId);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(th, &ctx);
ctx.Eip = (DWORD)absoluteoffset;
SetThreadContext(th, &ctx);
DWORD oprot;
VirtualProtect((LPVOID)absoluteoffset, 1, PAGE_EXECUTE_READWRITE, &oprot);
unsigned char byte[1] = {obyte};
WriteProcessMemory(ProcessInformation.hProcess,(LPVOID) absoluteoffset,(LPCVOID) byte, 1, 0);
VirtualProtect((LPVOID)absoluteoffset, 1, oprot,0);
#ifdef VERBOSE
printf("Removing bp.. %x\n", absoluteoffset);
#endif
CloseHandle(th);
FlushInstructionCache(ProcessInformation.hProcess,(LPVOID)absoluteoffset,1);
}
void SetBreakPoint(long absolute_offset){
set<long>::iterator it;
it = KnownBreakPoints.find(absolute_offset);
if(it!=KnownBreakPoints.end())
return;
unsigned char opcode;
ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)absolute_offset, &opcode, 1, 0);
if(opcode!=0xCC){
OrginalBytesCache.insert(std::make_pair((long)absolute_offset,opcode));
DWORD oldprot;
VirtualProtect((LPVOID)absolute_offset, 1, PAGE_EXECUTE_READWRITE, &oldprot);
WriteProcessMemory(ProcessInformation.hProcess,(LPVOID) absolute_offset, "\xCC",1,0);
VirtualProtect((LPVOID)absolute_offset, 1, oldprot,0);
FlushInstructionCache(ProcessInformation.hProcess,(LPCVOID)absolute_offset,1);
KnownBreakPoints.insert(absolute_offset);
#ifdef VERBOSE
printf("--> SET BP %x:\n",absolute_offset);
#endif
}
}
void Analyze(long absoluteoffset, DWORD dwThreadId){
_OffsetType offset = absoluteoffset-I_NT.OptionalHeader.BaseOfCode;
unsigned char *buf =NULL;
_ModuleInfo curmodule;
#ifdef VERBOSE
printf("attempting to analyze %x\n", absoluteoffset);
#endif
// detect in which module the breakpoint is located and loadup needed data + code
for(int ii = 0;ii<ModuleCount;ii++){
if(tracedmodules[ii].lBase < absoluteoffset && absoluteoffset < tracedmodules[ii].lCodeMaxAddress){
offset = absoluteoffset - tracedmodules[ii].lBase;// - tracedmodules[ii].lBase;
curmodule = tracedmodules[ii];
buf = tracedmodules[ii].PCodeCache;
break;
}
}
if(buf==NULL){
printf("error code not found..\n");
return;
}
buf += offset;
_CodeInfo ci = {0};
ci.code = buf;
ci.codeLen = curmodule.lSizeOfCode - offset;
ci.dt = Decode32Bits;
ci.codeOffset = offset;
ci.features = DF_STOP_ON_RET;
_DInst result[8096];
unsigned int instructions_count = 0;
set<long>::iterator it;
distorm_decompose(&ci, result, sizeof(result)/sizeof(result[0]), &instructions_count);
it = AnalyzedOffsets.find(curmodule.lBase+result[0].addr);
if(it!=AnalyzedOffsets.end())
return;
#ifdef VERBOSE
else
printf("--> Section TOP: %x\n", absoluteoffset);
#endif
for (unsigned int i = 0; i < instructions_count; i++) {
it = AnalyzedOffsets.find(curmodule.lBase+result[i].addr);
if(it!=AnalyzedOffsets.end())
return;
else
AnalyzedOffsets.insert(curmodule.lBase+result[i].addr);
if (result[i].flags == FLAG_NOT_DECODABLE){
printf("Unable to decode at %x\n", curmodule.lBase+result[i].addr);
return;
}
_DecodedInst inst;
distorm_format(&ci, &result[i], &inst);
#ifdef VERBOSE
printf("%x,",curmodule.lBase+result[i].addr);
printf("%s %s\n", inst.mnemonic.p, inst.operands.p);
printf("%x\n", result[i].opcode);
#endif
long absoluteoffset = curmodule.lBase+result[i].addr;
if (META_GET_FC(result[i].meta) == FC_CALL || META_GET_FC(result[i].meta) == FC_UNC_BRANCH || META_GET_FC(result[i].meta) == FC_CND_BRANCH)
{
_OffsetType absolute_target_address = 0;
// if you have a dll causing problems you can limit the loadup here to debug it
if(result[i].ops[0].type == O_REG || result[i].ops[0].type == O_DISP || result[i].ops[0].type == O_SMEM || result[i].ops[0].type == O_MEM || result[i].ops[0].type==O_DISP || result[i].ops[0].type==O_PC ){
// ops[0].index
// 16=eax;22=esi;23=edi;19=ebx;21=ebp;18=edx;17=ecx
it = BranchingDynamicBreakPoint.find(absoluteoffset);
if(it==BranchingDynamicBreakPoint.end()){
BranchingDynamicBreakPoint.insert(absoluteoffset);
BranchingDynamicRegister.insert(std::make_pair(absoluteoffset, result[i]));
SetBreakPoint(absoluteoffset);
return;
}
// compile optimizations?
if(META_GET_FC(result[i].meta)==FC_UNC_BRANCH)
return;
}
}
if (META_GET_FC(result[i].meta) == FC_RET){
#ifdef VERBOSE
printf("\nret found %x\n",(result[i].addr+curmodule.lBase) );
#endif
return;
}
}
return;
}
void GetModuleInfo()
{
DWORD needed = 0;
MODULEINFO mi;
// we know this from dllload events but yeh..
EnumProcessModules(ProcessInformation.hProcess, hmodules, 0, &needed);
hmodules = new HMODULE[needed/sizeof(HMODULE)];
EnumProcessModules(ProcessInformation.hProcess, hmodules, needed, &needed);
for (unsigned int i=0; i<needed/4; ++i)
GetModuleInformation(ProcessInformation.hProcess, hmodules[i], &mi, sizeof(mi));
}
long readreg(CONTEXT *ctx, long index){
long tooffset = 0;
switch(index){
case 16:
tooffset = ctx->Eax;
break;
case 22:
tooffset = ctx->Esi;
break;
case 23:
tooffset = ctx->Edi;
break;
case 19:
tooffset = ctx->Ebx;
break;
case 21:
tooffset = ctx->Ebp;
break;
case 18:
tooffset = ctx->Edx;
break;
case 17:
tooffset = ctx->Ecx;
break;
default:
printf("could not find dyn register data");
}
return tooffset;
}
void AnalyzeException(long offset, DWORD dwThreadId)
{
set<long>::iterator it;
_ModuleInfo ActualModule;
unsigned long iModuleNum = 0;
// detect in which module the breakpoint is located and loadup needed data + code
for(int ii = 0;ii<ModuleCount;ii++){
if(tracedmodules[ii].lBase < offset && offset < tracedmodules[ii].lCodeMaxAddress){
ActualModule = tracedmodules[ii];
memcpy(&iModuleNum, ActualModule.FileName, 8);
break;
}
}
iModuleNum++;
if(InScope(offset)){
// this decides stuff.. modulenum^ is to get differen values for different modules
// we can't use the true address due to aslr
long value = (iModuleNum^(offset-ActualModule.lBase));
it = VisitedBreakPoints.find(value);
if(it==VisitedBreakPoints.end())
VisitedBreakPoints.insert(value);
}
// handle "startup"
if(HasAnalyzedEntryPoint==false){
offset = (long)I_NT.OptionalHeader.AddressOfEntryPoint;
printf("Analyzing initial code section starting at: %x\n", offset);
Analyze(offset,dwThreadId);
HasAnalyzedEntryPoint = true;
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
GetModuleInfo();
return;
}
it = BranchingDynamicBreakPoint.find(offset);
if(it!=BranchingDynamicBreakPoint.end()){
#ifdef VERBOSE
printf("hit dyn bp %x \n", offset);
#endif
long tooffset = 0;
CONTEXT ctx;
char bytes[8];
HANDLE th = OpenThread(THREAD_ALL_ACCESS, NULL, dwThreadId);
ctx.ContextFlags = CONTEXT_FULL;
GetThreadContext(th, &ctx);
if(META_GET_FC(BranchingDynamicRegister[offset].meta) != FC_UNC_BRANCH){
Analyze(offset+BranchingDynamicRegister[offset].size, dwThreadId);
}
if(BranchingDynamicRegister[offset].ops[0].type == O_REG){
tooffset = readreg(&ctx, BranchingDynamicRegister[offset].ops[0].index);
}
else if(BranchingDynamicRegister[offset].ops[0].type == O_MEM || BranchingDynamicRegister[offset].ops[0].type==O_SMEM){
#ifdef VERBOSE
printf("index: %d\n", BranchingDynamicRegister[offset].ops[0].index);
printf("scale: %d\n", BranchingDynamicRegister[offset].scale);
printf("disp: %d\n", BranchingDynamicRegister[offset].disp);
#endif
long reg = readreg(&ctx, BranchingDynamicRegister[offset].ops[0].index);
if(BranchingDynamicRegister[offset].scale!=0)
reg = reg*BranchingDynamicRegister[offset].scale;
reg += BranchingDynamicRegister[offset].disp;
if(!ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)reg, bytes, 8, 0))
tooffset = 0;
else
memcpy(&tooffset, bytes, sizeof(tooffset));
}else if(BranchingDynamicRegister[offset].ops[0].type==O_DISP){
long regt = BranchingDynamicRegister[offset].disp;
#ifdef VERBOSE
printf("Absolute address: %x\n", regt);
#endif
if(!ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)regt, bytes, 8, 0))
tooffset = 0; // wont be handled..
else
memcpy(&tooffset, bytes, sizeof(tooffset));
}else if (BranchingDynamicRegister[offset].ops[0].type == O_PC) {
tooffset = INSTRUCTION_GET_TARGET(&BranchingDynamicRegister[offset]);
tooffset += ActualModule.lBase;
}else if (BranchingDynamicRegister[offset].flags & FLAG_RIP_RELATIVE)
tooffset = INSTRUCTION_GET_RIP_TARGET(&BranchingDynamicRegister[offset]);
else
printf("Odd type: %d\n", BranchingDynamicRegister[offset].ops[0].type);
CloseHandle(th);
if(InScope(tooffset)){
SetBreakPoint(tooffset);
dwContinueStatus = DBG_CONTINUE;
Analyze(tooffset, dwThreadId);
RemoveBreakPoint(offset, dwThreadId);
// we never rease these because they will / could be rehit with different values
// option 2: leave them.. instead of this on/off toggling
BackFlowLocation.insert(std::make_pair(tooffset,offset));
BackFlowOffset.insert(tooffset);
return;
}else // offset is not in scope
RemoveBreakPoint(offset, dwThreadId);
return;
}
if(InScope(offset)){
it = KnownBreakPoints.find(offset);
if(it==KnownBreakPoints.end()){
printf("not handled %x:/..", offset);
char b[8];
ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)offset, b, 8, 0);
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
return;
}
it = AnalyzedBreakPoints.find(offset);
if(it==AnalyzedBreakPoints.end()){
RemoveBreakPoint(offset, dwThreadId);
Analyze(offset, dwThreadId);
AnalyzedBreakPoints.insert(offset);
dwContinueStatus = DBG_CONTINUE;
}
else // unknown.. or already handled?
{
it = KnownBreakPoints.find(offset);
if(it!=KnownBreakPoints.end()){
dwContinueStatus = DBG_CONTINUE;
RemoveBreakPoint(offset, dwThreadId);
}else{
printf("not handled??");
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
}
}
}else {// not in scope / let os handle..
it = KnownBreakPoints.find(offset);
if(it!=KnownBreakPoints.end()){
RemoveBreakPoint(offset, dwThreadId);
AnalyzedBreakPoints.insert(offset);
dwContinueStatus = DBG_CONTINUE;
}else{
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
printf("outside scope.. set %x\n", DBG_EXCEPTION_NOT_HANDLED);
}
}
}
DWORD RvaToOffset(IMAGE_NT_HEADERS *NT, DWORD Rva)
{
DWORD Offset = Rva, Limit;
IMAGE_SECTION_HEADER *Img;
WORD i;
Img = IMAGE_FIRST_SECTION(NT);
if (Rva < Img->PointerToRawData)
return Rva;
for (i = 0; i < NT->FileHeader.NumberOfSections; i++)
{
if (Img[i].SizeOfRawData)
Limit = Img[i].SizeOfRawData;
else
Limit = Img[i].Misc.VirtualSize;
if (Rva >= Img[i].VirtualAddress &&
Rva < (Img[i].VirtualAddress + Limit))
{
if (Img[i].PointerToRawData != 0)
{
Offset -= Img[i].VirtualAddress;
Offset += Img[i].PointerToRawData;
}
return Offset;
}
}
return NULL;
}
DWORD Rva2Offset(DWORD dwRva, PIMAGE_SECTION_HEADER dwSecRva, USHORT uNumOfSecs)
{
for (USHORT i=0; i<uNumOfSecs; i++)
{
if (dwRva >= dwSecRva->VirtualAddress)
{
if (dwRva < dwSecRva->VirtualAddress + dwSecRva->Misc.VirtualSize)
return (DWORD)(dwRva - dwSecRva->VirtualAddress + dwSecRva->PointerToRawData) ;
}
dwSecRva ++ ;
}
return (DWORD)-1 ;
}
void ProcessDebugEvent( DEBUG_EVENT *debug_event)
{
char strEventMessage[MAX_PATH];
memset(strEventMessage, NULL, sizeof(strEventMessage));
switch(debug_event->dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
{
I_NT.OptionalHeader.AddressOfEntryPoint += (long)debug_event->u.CreateProcessInfo.lpBaseOfImage;
I_NT.OptionalHeader.BaseOfCode = (long)debug_event->u.CreateProcessInfo.lpBaseOfImage + I_NT.OptionalHeader.BaseOfCode;
printf("Create process: %s %x\nEntrypoint: %x BaseOfCode: %x\n", GetFileNameFromHandle(debug_event->u.CreateProcessInfo.hFile), debug_event->u.CreateProcessInfo.lpBaseOfImage, I_NT.OptionalHeader.AddressOfEntryPoint, I_NT.OptionalHeader.BaseOfCode);
_ModuleInfo NewModule;
NewModule.lBase = (long)I_NT.OptionalHeader.BaseOfCode;
NewModule.lCodeMaxAddress = (long)debug_event->u.CreateProcessInfo.lpBaseOfImage+I_NT.OptionalHeader.SizeOfCode;
NewModule.lSizeOfCode = (long)I_NT.OptionalHeader.SizeOfCode;
strcpy(NewModule.FileName, GetFileNameFromHandle(debug_event->u.CreateProcessInfo.hFile));
NewModule.PCodeCache = (unsigned char*)malloc(I_NT.OptionalHeader.SizeOfCode);
NewModule.bDll = false;
unsigned long NumBytesRead;
if(!ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)I_NT.OptionalHeader.BaseOfCode, NewModule.PCodeCache, I_NT.OptionalHeader.SizeOfCode, 0))
printf("Could not read processmemory..!\n");
tracedmodules[ModuleCount] = NewModule;
ModuleCount++;
}
break;
case CREATE_THREAD_DEBUG_EVENT:
printf("Thread 0x%x (Id: %d) created at: 0x%x\n",
debug_event->u.CreateThread.hThread,
debug_event->dwThreadId,
debug_event->u.CreateThread.lpStartAddress);
AnalyzeException((long)debug_event->u.CreateThread.lpStartAddress,debug_event->dwThreadId );
break;
case EXIT_THREAD_DEBUG_EVENT:
sprintf(strEventMessage, "Thread exit \n");
break;
case EXIT_PROCESS_DEBUG_EVENT:
printf("Process exit.. 0x%x blocks %d\n", debug_event->u.ExitProcess.dwExitCode, VisitedBreakPoints.size());
bContinueDebugging = false;
break;
case LOAD_DLL_DEBUG_EVENT:
{
char filename[MAX_PATH];
sprintf(filename, GetFileNameFromHandle(debug_event->u.LoadDll.hFile));
DllNameMap.insert(std::make_pair( debug_event->u.LoadDll.lpBaseOfDll, filename));
#ifdef VERBOSE
printf("%s -> %x\n", filename, debug_event->u.LoadDll.lpBaseOfDll);
#endif
// these are hardcoded so certain programs run through ok
// Agree, could make a filter input param :> // This Dll doesn't dig..
if(strstr(filename, "WINDOWS") == NULL && strstr(filename, "System32") == NULL && strstr(filename, "Windows")==NULL && strstr(filename, "OSPPC.DLL") == NULL)
{
HANDLE file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == INVALID_HANDLE_VALUE) {
printf("Could not open file %s (error %d)\n", filename, GetLastError());
}else{
LPVOID base;
PIMAGE_DOS_HEADER image_dos_header;
DWORD header;
HANDLE hMap = CreateFileMapping(debug_event->u.LoadDll.hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0);
if(hMap==NULL)
break;
base = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(base==NULL)
break;
image_dos_header = (PIMAGE_DOS_HEADER)base;
if (image_dos_header->e_magic != IMAGE_DOS_SIGNATURE)
UnmapViewOfFile(base);
else{
IMAGE_NT_HEADERS DLLI_NT_HEADER;
header = (DWORD)base + image_dos_header->e_lfanew;
memcpy(&DLLI_NT_HEADER, (void*)header, sizeof(IMAGE_NT_HEADERS));
_ModuleInfo LoadedModule;
LoadedModule.lBase = (long)debug_event->u.LoadDll.lpBaseOfDll+DLLI_NT_HEADER.OptionalHeader.BaseOfCode;
LoadedModule.lCodeMaxAddress = (long)debug_event->u.LoadDll.lpBaseOfDll+DLLI_NT_HEADER.OptionalHeader.BaseOfCode+DLLI_NT_HEADER.OptionalHeader.SizeOfCode;
LoadedModule.lSizeOfCode = DLLI_NT_HEADER.OptionalHeader.SizeOfCode;
// put true if you don't want analyzis of the internals.
LoadedModule.bDll = false;
strcpy(LoadedModule.FileName, filename);
LoadedModule.PCodeCache = (unsigned char*)malloc(LoadedModule.lSizeOfCode);
unsigned long NumBytesRead;
if(!ReadProcessMemory(ProcessInformation.hProcess,(LPCVOID)LoadedModule.lBase, LoadedModule.PCodeCache, LoadedModule.lSizeOfCode, 0))
printf("Could not read process memory..!\n");
DWORD dwExportDirectoryVA = DLLI_NT_HEADER.OptionalHeader.DataDirectory[0].VirtualAddress;
DWORD dwExportDirectoryVS = DLLI_NT_HEADER.OptionalHeader.DataDirectory[0].Size;
PIMAGE_SECTION_HEADER pCurSection ;
if (dwExportDirectoryVS != 0)
{
PIMAGE_SECTION_HEADER pImageSectionHeader = (PIMAGE_SECTION_HEADER) ((DWORD) base + image_dos_header->e_lfanew + sizeof(IMAGE_NT_HEADERS)) ;
pCurSection = pImageSectionHeader ;
USHORT sNumOfSections = DLLI_NT_HEADER.FileHeader.NumberOfSections ;
PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD) base + Rva2Offset(dwExportDirectoryVA, pCurSection, sNumOfSections)) ;
DWORD dwFunAddrTable ;
DWORD *vFunAddrTable ;
dwFunAddrTable = (DWORD) base + Rva2Offset(pImageExportDirectory->AddressOfFunctions, pImageSectionHeader, sNumOfSections) ;
vFunAddrTable = (DWORD *)dwFunAddrTable ;
for (DWORD j=0; j<pImageExportDirectory->NumberOfNames; j++)
{
SetBreakPoint((*vFunAddrTable)+(long)debug_event->u.LoadDll.lpBaseOfDll);
vFunAddrTable ++;
}
}
else
printf("No exports\n") ;
tracedmodules[ModuleCount] = LoadedModule;
ModuleCount++;
}
}
break;
}
}
break;
case UNLOAD_DLL_DEBUG_EVENT:
break;
case EXCEPTION_DEBUG_EVENT:
{
EXCEPTION_DEBUG_INFO& exception = debug_event->u.Exception;
#ifdef VERBOSE
printf("Exception at %x, exception-code: 0x%08x\n",
exception.ExceptionRecord.ExceptionAddress,
exception.ExceptionRecord.ExceptionCode);
#endif
switch( exception.ExceptionRecord.ExceptionCode)
{
case STATUS_BREAKPOINT:
AnalyzeException((long)exception.ExceptionRecord.ExceptionAddress,debug_event->dwThreadId );
break;
default:
AnalyzeException((long)exception.ExceptionRecord.ExceptionAddress, debug_event->dwThreadId);
}
break;
}
}
#ifdef VERBOSE
printf("Status: %s %x ",strEventMessage, dwContinueStatus);
#endif
ContinueDebugEvent(debug_event->dwProcessId, debug_event->dwThreadId, dwContinueStatus);
// Reset
dwContinueStatus = DBG_CONTINUE;
}
void WriteLog()
{
FILE *fp1;
fp1 = fopen(OutputFileName, "w");
set<long>::iterator it;
for (it = VisitedBreakPoints.begin() ; it != VisitedBreakPoints.end(); it++)
fprintf(fp1, "%x\n", *it);
fclose(fp1);
}
char* ReadFileName(char* p)
{
// parse out filename
char* tmp = strstr(p,"\\");
while(tmp!=NULL){
p = tmp+1;
tmp = strstr(p,"\\");
}
return p;
}
bool ReadFileNTHeader(char* ExecutablePath)
{
HANDLE hFile;
hFile = CreateFile(ExecutablePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Could not open file %s (error %d)\n", ExecutablePath, GetLastError());
return false;
}
LPVOID base;
PIMAGE_DOS_HEADER image_dos_header;
DWORD header;
HANDLE hMap = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0);
base = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
image_dos_header = (PIMAGE_DOS_HEADER)base;
if (image_dos_header->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("invalid DOS stub!\n");
UnmapViewOfFile(base);
return false;
}
header = (DWORD)base + image_dos_header->e_lfanew;
memcpy(&I_NT, (void*)header, sizeof(IMAGE_NT_HEADERS));
#ifdef VERBOSE
printf("Image NT Headers\n");
printf("Image Base: %x\n", I_NT.OptionalHeader.ImageBase);
printf("Entrypoint: %x\n", I_NT.OptionalHeader.AddressOfEntryPoint);
printf("Base: %x\n", I_NT.OptionalHeader.BaseOfCode);
printf("CodeSize: %x\n", I_NT.OptionalHeader.SizeOfCode);
#endif
return true;
}
int main(int argc, char **argv)
{
// argv handling -> :/
int argvCount = 1;
char ExecutablePath[MAX_PATH];
char Parameters[MAX_PATH];
char FileName[MAX_PATH];
ZeroMemory(ExecutablePath, MAX_PATH);
ZeroMemory(Parameters, MAX_PATH);
ZeroMemory(FileName, MAX_PATH);
ZeroMemory(OutputFileName, MAX_PATH);
if (argc != 9) {
showUsage();
return -1;
}
// ye ye this sucks, in a hurry :)
// prime sample of how not to handle arguments..
if (strcmp(argv[argvCount], "-f") == 0) {
argvCount++;
strncpy(ExecutablePath, argv[argvCount], strlen(argv[argvCount])+1);
argvCount++;
}else{
showUsage();
return -1;
}
if (strcmp(argv[argvCount], "-p") == 0) {
argvCount++;
// setting quotes around the params, you need to modify this to get more params than one passed.
strcat(Parameters, "\"");
strcat(Parameters, argv[argvCount]);
strcat(Parameters, "\"\0");
argvCount++;
}else{
showUsage();
return -1;
}
if (strcmp(argv[argvCount], "-o") == 0) {
argvCount++;
strcat(OutputFileName, argv[argvCount]);
argvCount++;
}else{
showUsage();
return -1;
}
if (strcmp(argv[argvCount], "-w") == 0) {
argvCount++;
TimeOut = atoi(argv[argvCount]);
}else{
showUsage();
return -1;
}
strcpy(FileName, ReadFileName(ExecutablePath));
EnableDebugPriv();
printf("Runtrace starting..\n");
printf("Command: %s %s\n", ExecutablePath, Parameters);
if(!ReadFileNTHeader(ExecutablePath))
return -1;
memset(&StartupInfo,0,sizeof(StartupInfo));
StartupInfo.cb= sizeof(StartupInfo);
char cmdline[MAX_PATH];
memset(&cmdline, 0, MAX_PATH);
strcat(cmdline, FileName);
strcat(cmdline, " ");
strcat(cmdline, Parameters);
if(!CreateProcess(ExecutablePath,cmdline, NULL, NULL, false, DEBUG_PROCESS, NULL,NULL,&StartupInfo,&ProcessInformation)) {
printf("Could not run the program.");
return -3;
}
CloseHandle(ProcessInformation.hThread);
DEBUG_EVENT debug_event = {0};
time_t t0 = time(NULL);
while(bContinueDebugging)
{
if (WaitForDebugEvent(&debug_event,1000))
ProcessDebugEvent(&debug_event);
time_t t1 = time(NULL);
double time_in_seconds = difftime(t1, t0);
if(time_in_seconds>TimeOut)
bContinueDebugging = false;
}
TerminateProcess(ProcessInformation.hProcess,0);
WriteLog();
printf("Done.\n");
return 0;
}