diff --git a/src/dbg/commands/cmd-misc.cpp b/src/dbg/commands/cmd-misc.cpp index 6f5a0fae..f3cfa21b 100644 --- a/src/dbg/commands/cmd-misc.cpp +++ b/src/dbg/commands/cmd-misc.cpp @@ -49,6 +49,7 @@ bool cbDebugHide(int argc, char* argv[]) } static duint LoadLibThreadID; +static duint FreeLibThreadID; static duint DLLNameMem; static duint ASMAddr; static TITAN_ENGINE_CONTEXT_t backupctx = { 0 }; @@ -77,6 +78,29 @@ static void cbDebugLoadLibBPX() wait(WAITID_RUN); } +static void cbDebugFreeLibBPX() +{ + HANDLE FreeLibThread = ThreadGetHandle((DWORD)FreeLibThreadID); +#ifdef _WIN64 + duint LibAddr = GetContextDataEx(FreeLibThread, UE_RAX); +#else + duint LibAddr = GetContextDataEx(FreeLibThread, UE_EAX); +#endif //_WIN64 + varset("$result", LibAddr, false); + backupctx.eflags &= ~0x100; + SetFullContextDataEx(FreeLibThread, &backupctx); + MemFreeRemote(ASMAddr); + ThreadResumeAll(); + //update GUI + DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), true); + //lock + lock(WAITID_RUN); + dbgsetforeground(); + PLUG_CB_PAUSEDEBUG pauseInfo = { nullptr }; + plugincbcall(CB_PAUSEDEBUG, &pauseInfo); + wait(WAITID_RUN); +} + bool cbDebugLoadLib(int argc, char* argv[]) { if(argc < 2) @@ -150,6 +174,106 @@ bool cbDebugLoadLib(int argc, char* argv[]) return ok; } +bool GetModuleEntry(MODULEENTRY32* me32, DWORD pID, char* module_name) +{ + HANDLE hModuleSnap; + bool found = false; + + hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pID); + if(hModuleSnap == INVALID_HANDLE_VALUE) + return false; + + if(Module32First(hModuleSnap, me32)) + { + do + { + if(_strcmpi(module_name, me32->szModule) == 0) + found = true; + } + while(!found && Module32Next(hModuleSnap, me32)); + } + + CloseHandle(hModuleSnap); + return found; +} + +bool cbDebugFreeLib(int argc, char* argv[]) +{ + MODULEENTRY32 unloadModule; + + ZeroMemory(&unloadModule, sizeof(MODULEENTRY32)); + unloadModule.dwSize = sizeof(MODULEENTRY32); + + if(argc < 2) + { + dputs(QT_TRANSLATE_NOOP("DBG", "Error: you must specify the name of the DLL to unload\n")); + return false; + } + + FreeLibThreadID = fdProcessInfo->dwThreadId; + HANDLE UnLoadLibThread = ThreadGetHandle((duint)FreeLibThreadID); + + if(!GetModuleEntry(&unloadModule, DbgGetProcessId(), argv[1])) + { + dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't get library handle")); + return false; + } + + ASMAddr = MemAllocRemote(0, 0x1000); + if(!ASMAddr) + { + dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't allocate memory in debuggee")); + return false; + } + + int size = 0; + int counter = 0; + duint FreeLibrary = 0; + char command[50] = ""; + char error[MAX_ERROR_SIZE] = ""; + + GetFullContextDataEx(UnLoadLibThread, &backupctx); + + if(!valfromstring("kernel32:FreeLibrary", &FreeLibrary, false)) + { + dputs(QT_TRANSLATE_NOOP("DBG", "Error: couldn't get kernel32:FreeLibrary")); + return false; + } + + // Arch specific asm code +#ifdef _WIN64 + sprintf_s(command, "mov rcx, %p", unloadModule.hModule); +#else + sprintf_s(command, "push %p", unloadModule.hModule); +#endif // _WIN64 + + assembleat(ASMAddr, command, &size, error, true); + counter += size; + +#ifdef _WIN64 + sprintf_s(command, "mov rax, %p", FreeLibrary); + assembleat(ASMAddr + counter, command, &size, error, true); + counter += size; + sprintf_s(command, "call rax"); +#else + sprintf_s(command, "call %p", FreeLibrary); +#endif // _WIN64 + + assembleat(ASMAddr + counter, command, &size, error, true); + counter += size; + + SetContextDataEx(UnLoadLibThread, UE_CIP, ASMAddr); + auto ok = SetBPX(ASMAddr + counter, UE_SINGLESHOOT | UE_BREAKPOINT_TYPE_INT3, (void*)cbDebugFreeLibBPX); + + ThreadSuspendAll(); + ResumeThread(UnLoadLibThread); + + unlock(WAITID_RUN); + + return ok; + +} + bool cbInstrAssemble(int argc, char* argv[]) { if(IsArgumentsLessThan(argc, 3)) diff --git a/src/dbg/commands/cmd-misc.h b/src/dbg/commands/cmd-misc.h index 4e93296a..658999b2 100644 --- a/src/dbg/commands/cmd-misc.h +++ b/src/dbg/commands/cmd-misc.h @@ -7,6 +7,7 @@ bool cbInstrZzz(int argc, char* argv[]); bool cbDebugHide(int argc, char* argv[]); bool cbDebugLoadLib(int argc, char* argv[]); +bool cbDebugFreeLib(int argc, char* argv[]); bool cbInstrAssemble(int argc, char* argv[]); bool cbInstrGpa(int argc, char* argv[]); diff --git a/src/dbg/x64dbg.cpp b/src/dbg/x64dbg.cpp index a4ff3bf8..550b47a7 100644 --- a/src/dbg/x64dbg.cpp +++ b/src/dbg/x64dbg.cpp @@ -398,6 +398,7 @@ static void registercommands() dbgcmdnew("HideDebugger\1dbh\1hide", cbDebugHide, true); //HideDebugger dbgcmdnew("loadlib", cbDebugLoadLib, true); //Load DLL + dbgcmdnew("freelib", cbDebugFreeLib, true); //Unload DLL dbgcmdnew("asm", cbInstrAssemble, true); //assemble instruction dbgcmdnew("gpa", cbInstrGpa, true); //get proc address diff --git a/src/gui/Src/Gui/SymbolView.cpp b/src/gui/Src/Gui/SymbolView.cpp index dfb14cfb..a1dca479 100644 --- a/src/gui/Src/Gui/SymbolView.cpp +++ b/src/gui/Src/Gui/SymbolView.cpp @@ -8,6 +8,7 @@ #include "LineEditDialog.h" #include #include +#include SymbolView::SymbolView(QWidget* parent) : QWidget(parent), ui(new Ui::SymbolView) { @@ -170,6 +171,20 @@ void SymbolView::setupContextMenu() mModuleList->mSearchList->addAction(mBrowseInExplorer); connect(mBrowseInExplorer, SIGNAL(triggered()), this, SLOT(moduleBrowse())); + mLoadLib = new QAction(DIcon("lib_load.png"), tr("Load library..."), this); + mLoadLib->setShortcutContext(Qt::WidgetWithChildrenShortcut); + this->addAction(mLoadLib); + mModuleList->mList->addAction(mLoadLib); + mModuleList->mSearchList->addAction(mLoadLib); + connect(mLoadLib, SIGNAL(triggered()), this, SLOT(moduleLoad())); + + mFreeLib = new QAction(DIcon("lib_free.png"), tr("Free library"), this); + mFreeLib->setShortcutContext(Qt::WidgetWithChildrenShortcut); + this->addAction(mFreeLib); + mModuleList->mList->addAction(mFreeLib); + mModuleList->mSearchList->addAction(mFreeLib); + connect(mFreeLib, SIGNAL(triggered()), this, SLOT(moduleFree())); + mYaraAction = new QAction(DIcon("yara.png"), tr("&Yara Memory..."), this); connect(mYaraAction, SIGNAL(triggered()), this, SLOT(moduleYara())); @@ -381,6 +396,8 @@ void SymbolView::moduleContextMenu(QMenu* wMenu) wMenu->addAction(mCopyPathAction); wMenu->addAction(mBrowseInExplorer); } + wMenu->addAction(mLoadLib); + wMenu->addAction(mFreeLib); wMenu->addAction(mYaraAction); wMenu->addAction(mYaraFileAction); wMenu->addAction(mEntropyAction); @@ -461,6 +478,44 @@ void SymbolView::moduleDownloadAllSymbols() DbgCmdExec("symdownload"); } +void SymbolView::moduleLoad() +{ + QString cmd; + if(!DbgIsDebugging()) + return; + + QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Dll Files (*.dll)")); + if(fileName.size() != 0) + { + cmd = "loadlib " + fileName; + DbgCmdExec(cmd.toUtf8().constData()); + } +} + +void SymbolView::moduleFree() +{ + QString cmd; + if(!DbgIsDebugging()) + return; + + QString moduleName = mModuleList->mCurList->getCellContent(mModuleList->mCurList->getInitialSelection(), 1); + if(moduleName.length() != 0) + { + QMessageBox::StandardButton reply; + QString question = "Are you sure you want to free the module: " + moduleName + "\r\nThis could bring an unexpected behaviour to your debugging sesion"; + reply = QMessageBox::question(this, + tr("Free Library").toUtf8().constData(), + question.toUtf8().constData(), + QMessageBox::Yes | QMessageBox::No); + if(reply == QMessageBox::Yes) + { + cmd = "freelib " + moduleName; + DbgCmdExec(cmd.toUtf8().constData()); + mSearchListView->mCurList->setRowCount(0); + } + } +} + void SymbolView::toggleBreakpoint() { if(!DbgIsDebugging()) diff --git a/src/gui/Src/Gui/SymbolView.h b/src/gui/Src/Gui/SymbolView.h index 4012e74e..064ef965 100644 --- a/src/gui/Src/Gui/SymbolView.h +++ b/src/gui/Src/Gui/SymbolView.h @@ -52,6 +52,8 @@ private slots: void moduleEntropy(); void emptySearchResultSlot(); void selectionGetSlot(SELECTIONDATA* selection); + void moduleLoad(); + void moduleFree(); signals: void showReferences(); @@ -81,6 +83,8 @@ private: QAction* mModSetPartyAction; QAction* mBrowseInExplorer; QAction* mFollowInMemMap; + QAction* mLoadLib; + QAction* mFreeLib; static void cbSymbolEnum(SYMBOLINFO* symbol, void* user); }; diff --git a/src/gui/images/lib_free.png b/src/gui/images/lib_free.png new file mode 100644 index 00000000..417dc779 Binary files /dev/null and b/src/gui/images/lib_free.png differ diff --git a/src/gui/images/lib_load.png b/src/gui/images/lib_load.png new file mode 100644 index 00000000..66e09008 Binary files /dev/null and b/src/gui/images/lib_load.png differ diff --git a/src/gui/resource.qrc b/src/gui/resource.qrc index c45dc839..05cfa470 100644 --- a/src/gui/resource.qrc +++ b/src/gui/resource.qrc @@ -278,5 +278,7 @@ images/uac.png images/hidetab.png images/variables.png + images/lib_load.png + images/lib_free.png