361 lines
13 KiB
C++
361 lines
13 KiB
C++
#include "addrinfo.h"
|
|
#include "debugger.h"
|
|
#include "console.h"
|
|
#include "memory.h"
|
|
#include "sqlhelper.h"
|
|
#include "breakpoint.h"
|
|
|
|
sqlite3* userdb;
|
|
|
|
///basic database functions
|
|
void dbinit()
|
|
{
|
|
//initialize user database
|
|
if(sqlite3_open(":memory:", &userdb))
|
|
{
|
|
dputs("failed to open database!");
|
|
return;
|
|
}
|
|
sqlloadsavedb(userdb, dbpath, false);
|
|
if(!sqlexec(userdb, "CREATE TABLE IF NOT EXISTS comments (id INTEGER PRIMARY KEY AUTOINCREMENT, mod TEXT, addr INT64 NOT NULL, text TEXT NOT NULL)"))
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
if(!sqlexec(userdb, "CREATE TABLE IF NOT EXISTS labels (id INTEGER PRIMARY KEY AUTOINCREMENT, mod TEXT, addr INT64 NOT NULL, text TEXT NOT NULL)"))
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
if(!sqlexec(userdb, "CREATE TABLE IF NOT EXISTS breakpoints (id INTEGER PRIMARY KEY AUTOINCREMENT, addr INT64 NOT NULL, enabled INT NOT NULL, singleshoot INT NOT NULL, oldbytes INT NOT NULL, type INT NOT NULL, titantype INT NOT NULL, mod TEXT, name TEXT)"))
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
dbsave();
|
|
bpenumall(0);
|
|
}
|
|
|
|
bool dbload()
|
|
{
|
|
if(!FileExists(dbpath))
|
|
{
|
|
dbinit();
|
|
return true;
|
|
}
|
|
return sqlloadsavedb(userdb, dbpath, false);
|
|
}
|
|
|
|
bool dbsave()
|
|
{
|
|
CreateDirectoryA(sqlitedb_basedir, 0); //create database directory
|
|
return sqlloadsavedb(userdb, dbpath, true);
|
|
}
|
|
|
|
void dbclose()
|
|
{
|
|
dbsave();
|
|
sqlite3_db_release_memory(userdb);
|
|
sqlite3_close(userdb); //close user database
|
|
}
|
|
|
|
///module functions
|
|
|
|
static std::vector<MODINFO> modinfo;
|
|
|
|
bool modload(uint base, uint size, const char* name)
|
|
{
|
|
if(!base or !size or !name or strlen(name)>=31)
|
|
return false;
|
|
MODINFO info;
|
|
info.base=base;
|
|
info.size=size;
|
|
strcpy(info.name, name);
|
|
_strlwr(info.name);
|
|
modinfo.push_back(info);
|
|
return true;
|
|
}
|
|
|
|
bool modunload(uint base)
|
|
{
|
|
int total=modinfo.size();
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
if(modinfo.at(i).base==base)
|
|
{
|
|
modinfo.erase(modinfo.begin()+i);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void modclear()
|
|
{
|
|
modinfo.clear();
|
|
}
|
|
|
|
bool modnamefromaddr(uint addr, char* modname)
|
|
{
|
|
if(!modname)
|
|
return false;
|
|
IMAGEHLP_MODULE64 modInfo;
|
|
memset(&modInfo, 0, sizeof(modInfo));
|
|
modInfo.SizeOfStruct=sizeof(IMAGEHLP_MODULE64);
|
|
if(!SymGetModuleInfo64(fdProcessInfo->hProcess, (DWORD64)addr, &modInfo))
|
|
return false;
|
|
_strlwr(modInfo.ModuleName);
|
|
strcpy(modname, modInfo.ModuleName);
|
|
return true;
|
|
}
|
|
|
|
uint modbasefromaddr(uint addr)
|
|
{
|
|
IMAGEHLP_MODULE64 modInfo;
|
|
memset(&modInfo, 0, sizeof(modInfo));
|
|
modInfo.SizeOfStruct=sizeof(IMAGEHLP_MODULE64);
|
|
if(!SymGetModuleInfo64(fdProcessInfo->hProcess, (DWORD64)addr, &modInfo))
|
|
return false;
|
|
return modInfo.BaseOfImage;
|
|
}
|
|
|
|
uint modbasefromname(const char* modname)
|
|
{
|
|
if(!modname)
|
|
return 0;
|
|
int total=modinfo.size();
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
if(!_stricmp(modinfo.at(i).name, modname))
|
|
return modinfo.at(i).base;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
///api functions
|
|
bool apienumexports(uint base, EXPORTENUMCALLBACK cbEnum)
|
|
{
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
VirtualQueryEx(fdProcessInfo->hProcess, (const void*)base, &mbi, sizeof(mbi));
|
|
uint size=mbi.RegionSize;
|
|
void* buffer=emalloc(size, "apienumexports:buffer");
|
|
if(!memread(fdProcessInfo->hProcess, (const void*)base, buffer, size, 0))
|
|
{
|
|
efree(buffer, "apienumexports:buffer");
|
|
return false;
|
|
}
|
|
IMAGE_NT_HEADERS* pnth=(IMAGE_NT_HEADERS*)((uint)buffer+GetPE32DataFromMappedFile((ULONG_PTR)buffer, 0, UE_PE_OFFSET));
|
|
uint export_dir_rva=pnth->OptionalHeader.DataDirectory[0].VirtualAddress;
|
|
uint export_dir_size=pnth->OptionalHeader.DataDirectory[0].Size;
|
|
efree(buffer, "apienumexports:buffer");
|
|
IMAGE_EXPORT_DIRECTORY export_dir;
|
|
memset(&export_dir, 0, sizeof(export_dir));
|
|
memread(fdProcessInfo->hProcess, (const void*)(export_dir_rva+base), &export_dir, sizeof(export_dir), 0);
|
|
unsigned int NumberOfNames=export_dir.NumberOfNames;
|
|
if(!export_dir.NumberOfFunctions or !NumberOfNames) //no named exports
|
|
return false;
|
|
char modname[256]="";
|
|
modnamefromaddr(base, modname);
|
|
uint original_name_va=export_dir.Name+base;
|
|
char original_name[deflen]="";
|
|
memset(original_name, 0, sizeof(original_name));
|
|
memread(fdProcessInfo->hProcess, (const void*)original_name_va, original_name, deflen, 0);
|
|
char* AddrOfFunctions_va=(char*)(export_dir.AddressOfFunctions+base);
|
|
char* AddrOfNames_va=(char*)(export_dir.AddressOfNames+base);
|
|
char* AddrOfNameOrdinals_va=(char*)(export_dir.AddressOfNameOrdinals+base);
|
|
for(DWORD i=0; i<NumberOfNames; i++)
|
|
{
|
|
DWORD curAddrOfName=0;
|
|
memread(fdProcessInfo->hProcess, AddrOfNames_va+sizeof(DWORD)*i, &curAddrOfName, sizeof(DWORD), 0);
|
|
char* cur_name_va=(char*)(curAddrOfName+base);
|
|
char cur_name[deflen]="";
|
|
memset(cur_name, 0, deflen);
|
|
memread(fdProcessInfo->hProcess, cur_name_va, cur_name, deflen, 0);
|
|
WORD curAddrOfNameOrdinals=0;
|
|
memread(fdProcessInfo->hProcess, AddrOfNameOrdinals_va+sizeof(WORD)*i, &curAddrOfNameOrdinals, sizeof(WORD), 0);
|
|
DWORD curFunctionRva=0;
|
|
memread(fdProcessInfo->hProcess, AddrOfFunctions_va+sizeof(DWORD)*curAddrOfNameOrdinals, &curFunctionRva, sizeof(DWORD), 0);
|
|
|
|
if(curFunctionRva>=export_dir_rva and curFunctionRva<export_dir_rva+export_dir_size)
|
|
{
|
|
char forwarded_api[deflen]="";
|
|
memset(forwarded_api, 0, deflen);
|
|
memread(fdProcessInfo->hProcess, (void*)(curFunctionRva+base), forwarded_api, deflen, 0);
|
|
int len=strlen(forwarded_api);
|
|
int j=0;
|
|
while(forwarded_api[j]!='.' and j<len)
|
|
j++;
|
|
if(forwarded_api[j]=='.')
|
|
{
|
|
forwarded_api[j]=0;
|
|
HINSTANCE hTempDll=LoadLibraryExA(forwarded_api, 0, DONT_RESOLVE_DLL_REFERENCES|LOAD_LIBRARY_AS_DATAFILE);
|
|
if(hTempDll)
|
|
{
|
|
uint local_addr=(uint)GetProcAddress(hTempDll, forwarded_api+j+1);
|
|
if(local_addr)
|
|
{
|
|
uint remote_addr=ImporterGetRemoteAPIAddress(fdProcessInfo->hProcess, local_addr);
|
|
cbEnum(base, modname, cur_name, remote_addr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cbEnum(base, modname, cur_name, curFunctionRva+base);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///comment functions
|
|
bool commentset(uint addr, const char* text)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr) or !text or strlen(text)>=MAX_COMMENT_SIZE-1)
|
|
return false;
|
|
if(!*text) //NOTE: delete when there is no text
|
|
return commentdel(addr);
|
|
char commenttext[MAX_COMMENT_SIZE]="";
|
|
sqlstringescape(text, commenttext);
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //comments without module
|
|
{
|
|
sprintf(sql, "SELECT text FROM comments WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
if(sqlhasresult(userdb, sql)) //there is a comment already
|
|
sprintf(sql, "UPDATE comments SET text='%s' WHERE mod IS NULL AND addr=%"fext"d", commenttext, addr);
|
|
else //insert
|
|
sprintf(sql, "INSERT INTO comments (addr,text) VALUES (%"fext"d,'%s')", addr, commenttext);
|
|
}
|
|
else
|
|
{
|
|
uint modbase=modbasefromaddr(addr);
|
|
uint rva=addr-modbase;
|
|
sprintf(sql, "SELECT text FROM comments WHERE mod='%s' AND addr=%"fext"d", modname, rva);
|
|
if(sqlhasresult(userdb, sql)) //there is a comment already
|
|
sprintf(sql, "UPDATE comments SET text='%s' WHERE mod='%s' AND addr=%"fext"d", commenttext, modname, rva);
|
|
else //insert
|
|
sprintf(sql, "INSERT INTO comments (mod,addr,text) VALUES ('%s',%"fext"d,'%s')", modname, rva, commenttext);
|
|
}
|
|
if(!sqlexec(userdb, sql))
|
|
{
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
return false;
|
|
}
|
|
GuiUpdateAllViews();
|
|
dbsave();
|
|
return true;
|
|
}
|
|
|
|
bool commentget(uint addr, char* text)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr) or !text)
|
|
return false;
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //comments without module
|
|
sprintf(sql, "SELECT text FROM comments WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
else
|
|
sprintf(sql, "SELECT text FROM comments WHERE mod='%s' AND addr=%"fext"d", modname, addr-modbasefromaddr(addr));
|
|
return sqlgettext(userdb, sql, text);
|
|
}
|
|
|
|
bool commentdel(uint addr)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr))
|
|
return false;
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //comments without module
|
|
sprintf(sql, "SELECT id FROM comments WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
else
|
|
{
|
|
uint modbase=modbasefromaddr(addr);
|
|
uint rva=addr-modbase;
|
|
sprintf(sql, "SELECT id FROM comments WHERE mod='%s' AND addr=%"fext"d", modname, rva);
|
|
}
|
|
int del_id=0;
|
|
if(!sqlgetint(userdb, sql, &del_id))
|
|
return false;
|
|
sprintf(sql, "DELETE FROM comments WHERE id=%d", del_id);
|
|
if(!sqlexec(userdb, sql))
|
|
{
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
return false;
|
|
}
|
|
GuiUpdateAllViews();
|
|
dbsave();
|
|
return true;
|
|
}
|
|
|
|
///label functions
|
|
bool labelset(uint addr, const char* text)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr) or !text or strlen(text)>=MAX_LABEL_SIZE-1)
|
|
return false;
|
|
if(!*text) //NOTE: delete when there is no text
|
|
return labeldel(addr);
|
|
char labeltext[MAX_LABEL_SIZE]="";
|
|
sqlstringescape(text, labeltext);
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //labels without module
|
|
{
|
|
sprintf(sql, "SELECT text FROM labels WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
if(sqlhasresult(userdb, sql)) //there is a label already
|
|
sprintf(sql, "UPDATE labels SET text='%s' WHERE mod IS NULL AND addr=%"fext"d", labeltext, addr);
|
|
else //insert
|
|
sprintf(sql, "INSERT INTO labels (addr,text) VALUES (%"fext"d,'%s')", addr, labeltext);
|
|
}
|
|
else
|
|
{
|
|
uint modbase=modbasefromaddr(addr);
|
|
uint rva=addr-modbase;
|
|
sprintf(sql, "SELECT text FROM labels WHERE mod='%s' AND addr=%"fext"d", modname, rva);
|
|
if(sqlhasresult(userdb, sql)) //there is a label already
|
|
sprintf(sql, "UPDATE labels SET text='%s' WHERE mod='%s' AND addr=%"fext"d", labeltext, modname, rva);
|
|
else //insert
|
|
sprintf(sql, "INSERT INTO labels (mod,addr,text) VALUES ('%s',%"fext"d,'%s')", modname, rva, labeltext);
|
|
}
|
|
if(!sqlexec(userdb, sql))
|
|
{
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
return false;
|
|
}
|
|
GuiUpdateAllViews();
|
|
dbsave();
|
|
return true;
|
|
}
|
|
|
|
bool labelget(uint addr, char* text)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr) or !text)
|
|
return false;
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //labels without module
|
|
sprintf(sql, "SELECT text FROM labels WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
else
|
|
sprintf(sql, "SELECT text FROM labels WHERE mod='%s' AND addr=%"fext"d", modname, addr-modbasefromaddr(addr));
|
|
return sqlgettext(userdb, sql, text);
|
|
}
|
|
|
|
bool labeldel(uint addr)
|
|
{
|
|
if(!IsFileBeingDebugged() or !memisvalidreadptr(fdProcessInfo->hProcess, addr))
|
|
return false;
|
|
char modname[35]="";
|
|
char sql[deflen]="";
|
|
if(!modnamefromaddr(addr, modname)) //labels without module
|
|
sprintf(sql, "SELECT id FROM labels WHERE mod IS NULL AND addr=%"fext"d", addr);
|
|
else
|
|
{
|
|
uint modbase=modbasefromaddr(addr);
|
|
uint rva=addr-modbase;
|
|
sprintf(sql, "SELECT id FROM labels WHERE mod='%s' AND addr=%"fext"d", modname, rva);
|
|
}
|
|
int del_id=0;
|
|
if(!sqlgetint(userdb, sql, &del_id))
|
|
return false;
|
|
sprintf(sql, "DELETE FROM labels WHERE id=%d", del_id);
|
|
if(!sqlexec(userdb, sql))
|
|
{
|
|
dprintf("SQL Error: %s\n", sqllasterror());
|
|
return false;
|
|
}
|
|
dbsave();
|
|
GuiUpdateAllViews();
|
|
return true;
|
|
}
|