지난 번 포스팅(http://www.xeronichs.com/2016/10/study-x64dbg-plugin-01.html)에서
플러그인(껍데기 뿐이지만;;)을 x64dbg 에 로딩하는 것까지 했습니다.
이번에는 '아~ 플러그인이 확실히 로딩되었구나~!!' 알 수 있도록...
눈에 보이는(?) 플러그인 '메뉴' 를 추가하는 방법을 알아보도록 하겠습니다.
그 전에...
32비트용, 64비트용 개발할 때마다 라이브러리 포함 코드를 바꾸는건 귀찮으니
이 부분부터 정리를 하고 넘어가죠~ ^^;;;;
매크로로 32비트 / 64비트 구별하기
64비트 프로젝트의 경우 기본적으로 '_WIN64' 라는 매크로가 정의되어 있는데요...
이걸로 32비트 / 64비트 프로젝트를 구별할 수 있습니다.
#include "pluginsdk\_plugins.h" #ifdef _WIN64 #pragma comment(lib, "pluginsdk\\x64dbg.lib") #else #pragma comment(lib, "pluginsdk\\x32dbg.lib") #endif //_WIN64
이렇게하면...
'_WIN64' 매크로가 있으면 64비트 프로젝트로 판단해서 "x64dbg.lib" 를 포함시키고,
없으면 32비트 프로젝트로 판단해서 "x32dbg.lib" 를 포함하게 됩니다.
이후에 다른 코드를 작성할 때도 32비트 / 64비트를 다르게 처리해야 될 경우,
이런 방식으로 매크로를 이용하면 됩니다 :)
지극히 개인적인 편의(?)를 위해 '프로젝트 속성' 에서 '출력 디렉터리', '중간 디렉터리' 를 살짝 바꿨습니다.
프로젝트 속성 '출력 디렉터리, 중간디렉터리' 변경 |
'플랫폼'이 하위폴더가 되도록 변경 |
x86(Release & Debug), x64(Release & Debug) 모든 구성, 플랫폼에 대해 변경을 했습니다.
'일괄빌드' 를 이용해서 x86, x64 프로젝트를 동시에 빌드를 해보면...
Debug, Release 폴더 안에 Win32, x64 폴더로 나뉘어져 결과물이 저장됩니다
Win32, x64 프로젝트 동시에 빌드 |
Release 폴더가 생성됨 |
Release 폴더 안에 Win32, x64 폴더가 생성됨 |
테스트를 좀 더 편하게(?) 하기 위해 프로젝트 폴더에 BAT 파일을 하나 만들어서...
32비트, 64비트 플러그인을 디버거 폴더에 각각 복사하도록 해뒀습니다.
@echo off copy .\Release\Win32\x64dbg_basic_plugin.dll C:\MyTools\x64dbg\release\x32\plugins\basic_plugin.dp32 copy .\Release\x64\x64dbg_basic_plugin.dll C:\MyTools\x64dbg\release\x64\plugins\basic_plugin.dp64 pause
플러그인 '메뉴' 구현
지난 번에 플러그인을 인식시키기 위해서 "pluginit" 이라는 export 함수를 구현을 했구요.
이번에는 디버거의 UI 쪽 정보를 얻기 위해 "plugsetup" 이라는 export 함수 를 구현해줘야 합니다.
HWND g_hwndDlg; int g_hMenu; int g_hMenuDisasm; int g_hMenuDump; int g_hMenuStack; //------------------------------------------------------------------- . . extern "C" __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct); . . //------------------------------------------------------------------- __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct) { g_hwndDlg = setupStruct->hwndDlg; // x64dbg 윈도우 핸들 g_hMenu = setupStruct->hMenu; // x64dbg 메인 메뉴 핸들 g_hMenuDisasm = setupStruct->hMenuDisasm; // x64dbg Disasm 창의 팝업메뉴 핸들 g_hMenuDump = setupStruct->hMenuDump; // x64dbg Dump 창의 팝업메뉴 핸들 g_hMenuStack = setupStruct->hMenuStack; // x64dbg Stack 창의 팝업메뉴 핸들 }
"plugsetup" 함수는 PLUG_SETUPSTRUCT 구조체를 인자로 사용하는데요...
이 구조체의 멤버 변수에 디버거 윈도우 핸들 및 각종 메뉴의 핸들이 담겨져 있습니다.
x64dbg UI 구성 |
메뉴를 추가할 때는 "_plugin_menuaddentry" 함수를 사용하며 사용법은 다음과 같습니다.
bool _plugin_menuaddentry(int hMenu, int hEntry, const char *title); |
- hMenu : 플러그인 메뉴를 추가할 대상의 핸들 - hEntry : 플러그인 메뉴 ID 값 (이후 메뉴에 대한 실행코드 작성 시 사용됨) - title : 화면에 보여지는 메뉴 텍스트 |
다음은 메뉴를 실제로 추가하는 코드입니다.
. . #define MENU_TEST1 0 #define MENU_TEST2 1 #define MENU_DISASM_TEST1 2 #define MENU_DISASM_TEST2 3 #define MENU_DUMP_TEST1 4 #define MENU_DUMP_TEST2 5 #define MENU_STACK_TEST1 6 #define MENU_STACK_TEST2 7 . . __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct) { . . . // 메인 메뉴 _plugin_menuaddentry(g_hMenu, MENU_TEST1, "Menu Test 1"); _plugin_menuaddseparator(g_hMenu); // 메뉴 분리선 _plugin_menuaddentry(g_hMenu, MENU_TEST2, "Menu Test 2"); // 디스어셈블 창 메뉴 _plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_TEST1, "Menu Disasm Test 1"); _plugin_menuaddseparator(g_hMenuDisasm); // 메뉴 분리선 _plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_TEST2, "Menu Disasm Test 2"); // 덤프 창 메뉴 _plugin_menuaddentry(g_hMenuDump, MENU_DUMP_TEST1, "Menu Dump Test 1"); _plugin_menuaddentry(g_hMenuDump, MENU_DUMP_TEST2, "Menu Dump Test 2"); // 스택 창 메뉴 _plugin_menuaddentry(g_hMenuStack, MENU_STACK_TEST1, "Menu Stack Test 1"); _plugin_menuaddentry(g_hMenuStack, MENU_STACK_TEST2, "Menu Stack Test 2"); }
플러그인이 종료될 때 정리작업을 해주는 "plugstop" export 함수도 작성을 해줍니다.
//------------------------------------------------------------------- . . extern "C" __declspec(dllexport) bool plugstop(void); . . //------------------------------------------------------------------- __declspec(dllexport) bool plugstop(void) { // 메뉴에 설정한 내용들 정리 _plugin_menuclear(g_hMenu); _plugin_menuclear(g_hMenuDisasm); _plugin_menuclear(g_hMenuDump); _plugin_menuclear(g_hMenuStack); return true; }
어제 작업했던 껍데기(?) 플러그인 코드에 오늘 내용을 덧붙이면 아래처럼 되겠네요~ :)
// plugin.cpp // //------------------------------------------------------------------- // basic plugin [ x64dbg plugin ] //------------------------------------------------------------------- #include <Windows.h> #include "pluginsdk\_plugins.h" #ifdef _WIN64 #pragma comment(lib, "pluginsdk\\x64dbg.lib") #else #pragma comment(lib, "pluginsdk\\x32dbg.lib") #endif //_WIN64 //------------------------------------------------------------------- #define plugin_name "BasicPlugin" #define plugin_version 1 #define MENU_TEST1 0 #define MENU_TEST2 1 #define MENU_DISASM_TEST1 2 #define MENU_DISASM_TEST2 3 #define MENU_DUMP_TEST1 4 #define MENU_DUMP_TEST2 5 #define MENU_STACK_TEST1 6 #define MENU_STACK_TEST2 7 int g_iPluginHandle; HWND g_hwndDlg; int g_hMenu; int g_hMenuDisasm; int g_hMenuDump; int g_hMenuStack; //------------------------------------------------------------------- extern "C" __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct); extern "C" __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct); extern "C" __declspec(dllexport) bool plugstop(void); //------------------------------------------------------------------- __declspec(dllexport) bool pluginit(PLUG_INITSTRUCT* initStruct) { initStruct->sdkVersion = PLUG_SDKVERSION; initStruct->pluginVersion = plugin_version; strcpy_s(initStruct->pluginName, 256, plugin_name); g_iPluginHandle = initStruct->pluginHandle; _plugin_logprintf("[BasicPlugin] pluginHandle : %d\n", g_iPluginHandle); return true; } __declspec(dllexport) void plugsetup(PLUG_SETUPSTRUCT* setupStruct) { g_hwndDlg = setupStruct->hwndDlg; g_hMenu = setupStruct->hMenu; g_hMenuDisasm = setupStruct->hMenuDisasm; g_hMenuDump = setupStruct->hMenuDump; g_hMenuStack = setupStruct->hMenuStack; // 메인 메뉴 _plugin_menuaddentry(g_hMenu, MENU_TEST1, "Menu Test 1"); _plugin_menuaddseparator(g_hMenu); _plugin_menuaddentry(g_hMenu, MENU_TEST2, "Menu Test 2"); // 디스어셈블 창 메뉴 _plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_TEST1, "Menu Disasm Test 1"); _plugin_menuaddseparator(g_hMenuDisasm); _plugin_menuaddentry(g_hMenuDisasm, MENU_DISASM_TEST2, "Menu Disasm Test 2"); // 덤프 창 메뉴 _plugin_menuaddentry(g_hMenuDump, MENU_DUMP_TEST1, "Menu Dump Test 1"); _plugin_menuaddentry(g_hMenuDump, MENU_DUMP_TEST2, "Menu Dump Test 2"); // 스택 창 메뉴 _plugin_menuaddentry(g_hMenuStack, MENU_STACK_TEST1, "Menu Stack Test 1"); _plugin_menuaddentry(g_hMenuStack, MENU_STACK_TEST2, "Menu Stack Test 2"); } __declspec(dllexport) bool plugstop(void) { _plugin_menuclear(g_hMenu); _plugin_menuclear(g_hMenuDisasm); _plugin_menuclear(g_hMenuDump); _plugin_menuclear(g_hMenuStack); return true; } //------------------------------------------------------------------- // DllMain //------------------------------------------------------------------- BOOL WINAPI DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved) { return TRUE; }
이 코드를 빌드를 해서 디버거 플러그인 폴더에 복사해서 실행을 해보면 메뉴가 뜨는 걸 볼 수 있을 겁니다 :)
'메인 메뉴' 의 플러그인 메뉴 |
'Disasm 창 팝업 메뉴' 의 플러그인 메뉴 |
'Dump 창 팝업 메뉴' 의 플러그인 메뉴 |
'Stack 창 팝업 메뉴' 의 플러그인 메뉴 |
이번에는 여기까지~~ 플러그인 '메뉴' 를 추가하는 방법을 알아봤구요...
다음에는 이렇게 추가한 '메뉴' 를 클릭할 때, 특정 동작을 실행시키는 걸 알아보도록 하겠습니다.
[ BasicPlugin 소스 다운로드 ]