首页
社区
课程
招聘
[原创]二次开发之给Windows窗口程序加密码锁
发表于: 2024-5-7 10:23 3605

[原创]二次开发之给Windows窗口程序加密码锁

2024-5-7 10:23
3605

描述

  • 原程序是windows下常见的采用事件循环机制的窗口程序,通过二次开发,给这个程序上锁,加上一个验证身份框,只有输对用户名密码,才能正常使用程序功能

原程序

  • 创建一个窗口,加入事件循环,响应窗口消息
  • 代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <windows.h>
#include <cstdio>
 
#define ID_EDIT 1 // Added this line to define ID_EDIT
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;
    HWND hEdit;
 
    //Step 1: Registering the Window Class
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "WindowClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
 
    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "WindowClass",
        "成功",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 500, 300,
        NULL, NULL, hInstance, NULL);
 
    if (hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
 
    // Step 3: Creating the Edit Control
    hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
        WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
        50, 50, 200, 100, hwnd, (HMENU)ID_EDIT, hInstance, NULL);
 
    if (hEdit == NULL)
    {
        MessageBox(NULL, "Edit Control Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
 
    // Step 4: Setting the Text of the Edit Control
    SendMessage(hEdit, WM_SETTEXT, NULL, (LPARAM)"恭喜你成功进入游戏!");
 
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
 
    for (int i = 0; i++; i < 10) {
        printf("第%d轮\n", i);
    }
    // Step 5: The Message Loop
    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
 
    return Msg.wParam;
}
  • 运行效果:运行Msg.exe,效果如下

对原程序进行二次开发,上锁

原理

  • 将要添加的功能编写为dll,注入到目标程序中
  • 在目标程序中找到一个合适的位置,调用dll中的函数,特别要注意堆栈平衡和参数的设置,还要注意不能破坏原有程序的指令,如果原有指令被覆盖,需要在调用dll函数后再将被覆盖的指令执行一遍

步骤

  • 编写dll:创建一个注册窗口函数MyCreateWindow,GetMessage部分不用写,用原程序的就行,并编写窗口回调函数MyWndProc,在其中处理用户输入,将上述两个函数编写到dll中导出,只需要给原程序添加一个对MyCreateWindow的调用,就可以创建注册窗口并响应用户输入,dll部分的代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <windows.h>
 
BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
 
extern "C" __declspec(dllexport) LRESULT CALLBACK MyWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND hwndUsername, hwndPassword, hwndButton;
    switch (message)
    {
    case WM_CREATE:
        hwndUsername = CreateWindow(TEXT("edit"), NULL,
            WS_CHILD | WS_VISIBLE | WS_BORDER,
            50, 50, 200, 25,
            hwnd, (HMENU)1, NULL, NULL);
        hwndPassword = CreateWindow(TEXT("edit"), NULL,
            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_PASSWORD,
            50, 100, 200, 25,
            hwnd, (HMENU)2, NULL, NULL);
        hwndButton = CreateWindow(TEXT("button"), TEXT("OK"),
            WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
            100, 150, 80, 25,
            hwnd, (HMENU)3, NULL, NULL);
        break;
    case WM_COMMAND:
        if (LOWORD(wParam) == 3)
        {
            TCHAR username[20], password[20];
            GetWindowText(hwndUsername, username, 20);
            GetWindowText(hwndPassword, password, 20);
            if (lstrcmp(password, TEXT("test")) != 0) {
                MessageBox(hwnd, TEXT("密码错误,退出程序!"), TEXT("Error"), MB_OK);
                exit(0);
            }
            else {
                MessageBox(hwnd, TEXT("密码正确,继续你的游戏!"), TEXT("Success"), MB_OK);
                SendMessage(hwnd, WM_CLOSE, 0, 0);
            }
        }
        break;
    case WM_DESTROY:
        exit(0);
        break;
    case WM_CLOSE:
        exit(0);
        break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}
 
extern "C" __declspec(dllexport) int WINAPI MyCreateWindow(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("HelloWin");
    HWND hwnd2;
    WNDCLASS wndclass;
 
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = MyWndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
 
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }
 
    hwnd2 = CreateWindow(szAppName,                  // window class name
        TEXT("The Hello Program"), // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        CW_USEDEFAULT,              // initial x position
        CW_USEDEFAULT,              // initial y position
        500,              // initial x size
        300,              // initial y size
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL);                      // creation parameters
 
    ShowWindow(hwnd2, iCmdShow);
    UpdateWindow(hwnd2);
 }
  • 将dll注入到原程序:通过PE Tools,在输入表中添加MsgDll和MyCreateWindow函数
  • patch原程序:运行x64dbg,在目标程序中选取一处存放不重要代码的位置(更好的做法是选取区块间的间隙并跳转执行,这里偷个懒随便找了个不重要的赋值语句(1B40处))
  • 首先给我们的MyCreateWindow函数传入参数,这里需要传入WinMain的四个参数,可以看到程序刚进入函数时将四个参数保存到了栈上
  • 那么我们只要从栈上取出四个参数并放入寄存器,就可以给MyCreateWindow提供参数了
  • 放好参数好,准备写入call MyCreateWindow,call指令的十六进制为ff 15,地址的计算结果为1552A
  • 写入call MyCreateWindow,可以看到反汇编器成功解析处call函数的地址
  • 由于前面写入的指令破坏了后面的指令,所以加一个jmp跳过这些坏字节
  • 被调用函数MyCrateWindow已经进行了堆栈平衡,所以不需要在调用函数中抬高rsp
  • 本来到这里已经可以了,但出了点小问题,程序中间将rsp抬高了258个字节,所以后面从栈上取参数的位置也要相应变化,加上258个字节
  • 修改后程序如下

运行效果

  • 将MsgDll同Msg.exe放到同一目录下,运行Msg.exe,可以看到在程序正常窗口前,弹出了密码验证框,输错后程序退出

[峰会]看雪.第八届安全开发者峰会10月23日上海龙之梦大酒店举办!

最后于 2024-5-7 10:31 被korma编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (3)
雪    币: 148
活跃值: (1883)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
虽然我不懂网络安全 但是 这种给程序上锁的方式很有意思 
2024-5-7 12:57
0
雪    币: 183
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
哪里上锁了?
2024-5-14 13:37
0
雪    币: 242
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
lanmanck 哪里上锁了?
我也奇怪的,应该是楼主图传错了。这样的操作我之前也做过,在一个窗口上面添加自己的按钮和编辑框
2024-6-11 11:34
0
游客
登录 | 注册 方可回帖
返回
//