지난 번 포스팅(
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 소스 다운로드 ]