之前在学习windows编程的时候已经写过对话框的创建了,其中包括了对话框的分类,原理等等,大家可以去看一下:【windows编程之对话框】对话框原理,对话框的创建。原理今天就讲的不是很多了,直接给大家给出步骤+代码,如果大家不懂原理的话,可以去那一片博客中看一下。
我们今天主要讲解资源文件(对话框)的创建步骤,以及在逆向过程中很有用的一种断点方式:消息断点。
一.创建对话框
- 可视化界面绘制对话框
- 我们在可视化界面绘制对话框之后,实际上就可以使对话框显示了:
我们使用DialogBox
函数即可让会话框显示:
DialogBox(hInst, (LPCWSTR)IDD_DIALOG1, NULL, DiaLogProc); • 1
实际上这里是模式对话框,是根据返回值退出的,具体可以看着一篇博客:【windows编程之对话框】对话框原理,对话框的创建。
二.获取文本框内容
我们的应用程序,很多时候都需要获取文本框中的内容做判断,比如判断密码是否正确等等,那么我们怎么获取文本框的内容呢?
- 1.获取文本框句柄
使用GetDlgItem()
函数,可以获取指定文本框的句柄,MSDN官方文档解释该函数
HWND GetDlgItem( [in, optional] HWND hDlg, [in] int nIDDlgItem );
参数解释:
- hDlg:对话框句柄
- nIDDlgItem:要检索的控件标识符
返回值:HWND,指定对话框的窗口句柄
在获取到文本框句柄后,就可以获取文本框内容了:
- 获取文本内容:
使用GetWindowText()
函数,MSDN官方文档解释该函数
int GetWindowTextA( [in] HWND hWnd, [out] LPSTR lpString, [in] int nMaxCount );
参数解释:
- hWnd:对话框句柄,我们上一个函数的返回值
lpString:注意这是一个OUT类型的参数,接收文本的缓冲区,在使用函数之前,我们需要申请一块内存,用于接收文本内容
nMaxCount:复制到缓冲区的最大字符数,包括NULL字符。
三.消息断点(附对话框回调函数的寻找)
我们之前一直是找到回调函数之后,根据消息堆栈对应用程序进行条件断点,但是有很多情况下,应用程序都很复杂,我们很难找到回调函数,那今天我们就来带领大家学习一种新的断点方式:消息断点,我们不需要找到回调函数当应用程序接收到消息后,会自动断点,以便我们的逆向工作。
这里先给大家一个我自己编写的应用程序,我们后续做消息断点就使用这个应用程序,大家注意生成应用程序的时候发布为Release版本,因为大多数Debug版本的程序,寻址方式与Release版本不同(Debug大多使用ebp寻址,而Release版大多使用esp寻址,而我们平时做逆向肯定做的是Release版):
很好用的一个软件(肯定不是恶意软件)
// 破解一切.cpp : 定义应用程序的入口点。 // #include "framework.h" #include "破解一切.h" #include "Resource.h" int x = 0; int y = 0; #define MAX_LOADSTRING 100 int style; // 全局变量: HINSTANCE hInst; // 当前实例 WCHAR szTitle[MAX_LOADSTRING]=TEXT("好用的破解软件"); // 标题栏文本 WCHAR szWindowClass[MAX_LOADSTRING]=TEXT("main"); // 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK DiaLogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { style = nCmdShow; // TODO: 在此处放置代码。 // 初始化全局字符串 MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MY)); MSG msg; // 主消息循环: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目标: 注册窗口类。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEXW wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY)); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MY); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); WNDCLASSEXW sc = { 0 }; sc.style = CS_HREDRAW | CS_VREDRAW; sc.lpfnWndProc = WndProc; sc.cbClsExtra = 0; sc.cbWndExtra = 0; sc.hInstance = hInstance; sc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MY)); sc.hCursor = LoadCursor(nullptr, IDC_ARROW); sc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); sc.lpszMenuName = MAKEINTRESOURCEW(IDC_MY); sc.lpszClassName = szWindowClass; sc.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassExW(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目标: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { hInst = hInstance; // 将实例句柄存储在全局变量中 HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,x,y, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } DialogBox(hInst, (LPCWSTR)IDD_DIALOG1, NULL, DiaLogProc); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目标: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: { int wmId = LOWORD(wParam); switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; case ID_32774: { int i, j; for (i = 0; i < 100; x += 200) { for (j = 0; j < 30; y += 36) { HWND MyhWnd = CreateWindowW(szWindowClass, (LPCWSTR)TEXT("谁叫你乱点!!!"), WS_OVERLAPPEDWINDOW, x, y, 300, 40, nullptr, nullptr, hInst, nullptr); ShowWindow(MyhWnd, style); // Sleep(100); j++; } y = 0; i++; } break; } default: return DefWindowProc(hWnd, message, wParam, lParam); } } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); // TODO: 在此处添加使用 hdc 的任何绘图代码... EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } //对话框处理函数 INT_PTR CALLBACK DiaLogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_COMMAND: { if (wParam == IDR_ACCELERATOR1) { EndDialog(hwndDlg, 100); break; } if (wParam == IDI_SMALL) { int i, j; MessageBox(hwndDlg, TEXT("你确定要退出码?"), NULL, MB_OK); for (i = 0; i < 100; x+=200) { for (j = 0; j < 30; y += 36) { HWND MyhWnd = CreateWindowW(szWindowClass, (LPCWSTR)TEXT("妈的让你退出!!!"), WS_OVERLAPPEDWINDOW, x, y, 300,40, nullptr, nullptr, hInst, nullptr); ShowWindow(MyhWnd, style); // Sleep(100); j++; } y = 0; i++; } PostMessage(NULL, WM_QUIT, 0, 0); EndDialog(hwndDlg, 100); break; } } case WM_SYSCOMMAND: { PostQuitMessage(0); } } return FALSE; }
相信稍微有点基础的都能看出来我编写的这个应用程序不是做什么好事的。
由于我不是做开发的,所以代码写的很烂,但是我们做底层的,了解了基本原理就可以了,这个软件我会在后续做很多改进,大家可以关注我的文章,待程序改进好之后,大家可以去“玩儿玩儿”。
那我们就是用这个应用程序来给大家讲解消息断点:
- 首先,我们来看看这个应用程序:
当打开之后,会弹出这样一个对话框,提示输入账号和密码: - 当然,你肯定不知道账号和密码,当然我也不知道,因为我还没写账号密码的判定,那肯定会去点“直接破解进去”这个按钮了,当点击这个按钮之后,应用程序主窗口就弹出来了:
里面有一个释放病毒,实际上不是什么病毒,我们今天不研究这个,这里就不细细讲解了,我们来看一下另一个按钮:取消按钮,这里就是个坑了: - 当我们点击取消按钮的时候,会弹出一个提示框:
这里就是一个坑了,不管你点击哪里,都会让这个恶意代码运行,我们来看看运行之后是什么样的:
不管点击哪里,都会让这段代码运行,会弹出满屏的窗口,大家也不用担心,应用程序会自动退出。