所有教程由网友发布,仅供参考,请谨慎采纳。科创不对教程的科学性、准确性、可靠性负责。
C++自动破解锁机工具[HOOK WINDOWS API]
章鱼wheat2024/07/08原创 软件综合 IP:江西
关键词
锁机破解用户锁硬盘锁病毒
HOOKC++WINDOWS API

背景:

    不知为何,儿时记忆突然如潮水般涌入心头,使我感慨万分。

    记忆其中之一的关键字就为'锁机',其二就为'破解',由此而延伸回忆出儿时曾想过的目标 '编写自动破解锁机工具'。  以前儿时在某个与破解有关的QQ群中看到过有人使用易语言编写的自动破解锁机程序,儿时的我也想编写一个,不过由于回忆不起的未知原因并未完成。 此文就为儿时记忆所激发而成,实现那儿时愿景~~~


使用工具:

    Visual Studio 2022

    VMware

    ollydbg

    Xenos

首先肯定是需要知锁机病毒其原理,再根据其原理编写应对方针

中文网络中常见的锁机病毒皆为易语言编写,其源码很容易在互联网中找到。具体的锁机病毒还有更详细的分类:|用户锁|硬盘锁|屏幕锁| 前两个最为常见,逐个分析



用户锁:

典型例子为 

image.png

如何用易语言制作简单的锁机软件_360新知 (XXXXXX)

将例子编译成可执行文件,将其上传至云沙箱可知

image.png (据我所知只有此云沙箱会显示具体的api,其余的云沙箱都模糊的写到"创建进程")

调用了名为"CreateProcessInternalW"的api
其中的CommandLine参数就为执行的命令 “C:\Windows\system32\net1 user admin 123456”

不过此文并不是HOOK “CreateProcessInternalW” 而是最基础的 "CreateProcessA" 

image.png

打开OD,断点 "CreateProcessA",运行程序等待触发断点,断下后可发现清晰的结构,其中的“CommandLine”即为执行的命令。

image.png

知道其调用的api后就可使用C++编写针对性程序

编写用户锁C++ DLL程序:

最常见的用于|拦截|监视|劫持|api的方法为'Inline Hook',此程序就是依据此原理展开的。

首先需要去学习学习(抄袭抄袭)有关"C++ HOOK api"的信息  搜索相关信息可发现(找半天)

C/C++ Inline Hook 钩子编写技巧 - lyshark - 博客园 (XXXXXXXXXXX)

Basic Windows API Hooking. API hooking has been covered… | by Jayson Hurst | Geek Culture | Medium (我会认为这个更加直白易懂)

[原创]万字长文!inlinehook看这一篇足够了!-软件逆向-看雪-安全社区|安全招聘|XXXXXXXXXX(此程序参考[抄袭]此贴)

更为具体为此:

image.png


CreateProcessA 函数 (processthreadsapi.h) - Win32 apps | Microsoft Learn

image.png

image.png

将SetWindowTextA 更换为我们的 CreateProcessA   得以下代码

#include <Windows.h>
#include <string>
#include <iostream>
#include "pch.h"
#include "stdio.h"
#include<cstring>
#include<sstream>
using namespace std;
DWORD jump = 0;

__declspec(naked) bool _stdcall Transfer(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation)
{
    __asm {
        mov edi, edi
        push ebp
        mov ebp, esp
        mov ebx, jump
        jmp ebx
    }
}


BOOL WINAPI hookedCreateProcessA(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFOA lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
) {


    std::string messageA = " Commnd: " + std::string(lpCommandLine);
    //std::string messageB = std::string(lpApplicationName) + messageA;

    MessageBoxA(NULL, messageA.c_str(), "捕获执行命令", MB_OK);
    LPSTR lpCommandLineA = const_cast<LPSTR>("");

    BOOL result = Transfer(lpApplicationName, lpCommandLineA, lpProcessAttributes,
        lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
        lpCurrentDirectory, lpStartupInfo, lpProcessInformation);

    return result;
}



bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid)
{
    HMODULE hwnd = GetModuleHandle(TEXT("kernel32.dll"));
    DWORD base = (DWORD)GetProcAddress(hwnd, "CreateProcessA");
    DWORD oldProtect = 0;

    char message[256];
    //sprintf_s(message, "CreateProcessA address: %08X", base);
    //MessageBoxA(NULL, message, "Information", MB_OK);


    if (VirtualProtect((LPVOID)base, 5, PAGE_EXECUTE_READWRITE, &oldProtect))
    {
        DWORD value = (DWORD)hookedCreateProcessA - base - 5;
        jump = base + 5;
        __asm {
            mov eax, base
            mov byte ptr[eax], 0xe9
            inc eax
            mov ebx, value
            mov dword ptr[eax], ebx
        }
        VirtualProtect((LPVOID)base, 5, oldProtect, &oldProtect);
    }
    return true;
}

由于对方运行在32位 所以我们的DLL也得编译成32位的

image.png

image.png

编译得

attachment icon CommandHook.dll 12.00KB DLL 0次下载

使用现成工具 Xenos 进行注入 可以看见成功的拦截了执行命令

image.png

顺带看看是否符合相关帖子描述

image.png

image.png

image.png

image.png

很显然的符合

image.png

跳回代码就是像原来的一样,前面三个像是一个固定的'头'。后面的就是将jump赋值给ebx, jmp ebx 就是跳到ebx的位置 。这个jump值就是 75842D70 +5 就等于POP的位置,相当于跳过了上面的 “jmp到dll函数”,再往下走就是跳转到正常的"CreateProcessA"了。

为什么有前面这三个东西:
Win32API起始处的mov edi, edi与用户空间InlineHook - 孤影对酌 - 博客园 (XXXXXXXXXXX) 

栈帧ebp,esp详解_压入ret后,继续压入当前ebp,然后用当前esp代替ebp-CSDN博客


硬盘锁:

硬盘锁几乎都是使用一个名叫'无名模块'中的一个函数'物理硬盘_新版无名神锁',易语言的模块实际上是可以直接转换为源代码的。

attachment icon AAAA无名模块.ec 252.49KB EC 0次下载

通过网络搜索的转换工具转换可得:

attachment icon 易分析_AAAA无名模块.e 264.70KB E 0次下载

image.png

image.png

其中最关键的为 "物理硬盘_写硬盘扇区" 

image.png

可以直观的看到他调用了什么api,具体搜索搜相关api的功能就会发现,我们只需要hook WriteFile 即可。

image.png

image.png

image.png

WriteFile 函数 (fileapi.h) - Win32 apps | Microsoft Learn

查看官方文件可知其lpBuffer为写入数据的地址

先用OD看一看

第一次

image.png

搜索内存 然后转到对应地址

image.png

可以发现并没有什么有用信息,因为在上面的易语言源码中可以看到,写了两次数据,第一个是 "匿名局部变量_4 = 物理硬盘_读硬盘扇区 (0, 1)" ,第二个才是真正的有关数据。

第二次触发断点 

image.png

搜索内存然后转到对应地址

image.png

成功找到,其中AAAAA123为密码 BBBB234为显示信息  错误信息查看上面的源码可知 实际上是'参考' 也就类似windows api的那种out 返回有没有加密成功的 那时候我没看见所以添加了一串字符串

image.png

编写硬盘锁C++ DLL程序:

image.png

如何实现C++读写进程内存值_c++读取内存中的数值-CSDN博客

由于我后面的fwrite是需要提供指针的,而这个文章内是int变量,我就改成了 char*,结果并未返回出正确的指针或者是fwirte读不了那个指针。

询问了一下chatgpt,直接变成主动提供了,创建了一个指针,然后输入进了为out的lpBuffer。结果居然还成功了。

image.png

chatgpt提供的方法

image.png

image.png

之后就更离奇了 

char *bufferContentB = new char[nNumberOfBytesToWrite];  我抄了一下上面的代码创建了一个空的新指针给到下面的

BOOL result = Transfer(hFile, bufferContentB, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);

结果写出的是和lpBuffer一模一样的数据,重启一样锁机了。。。 (我怀疑都不用添加ReadProcessMemory,直接用定义的新指针就可以写出了)

问了一下chatgpt后给我加上了memset,结果一看output.txt全是空格了,写出txt可是在前面,并且还是追加。。。 

顺带我加上了个信息框 看看它通过了几次,结果就是弹出了无数次的信息框。。。  (实际上在DllMain添加个信息框也会发现被执行了好几遍)

我还尝试过直接return true,结果就是写出的文本内容不对,写出的应该只有第一次执行的“物理硬盘_写硬盘扇区”。

要找出这些原因怕是耗时巨大,所以就直接蒙着眼睛当看不见说:“算了虚拟机无所谓,点个恢复快照的事情,让它正常写出,能读出数据写到txt文本就行,直接不做了睡大觉。”

#include <Windows.h>
#include <string>
#include <iostream>
#include "pch.h"
#include "stdio.h"
#include <cstring>
#include <sstream>
#include <fstream>
using namespace std;
DWORD jump = 0;
__declspec(naked) BOOL _stdcall Transfer(
    HANDLE hFile,
    LPCVOID lpBuffer,
    DWORD nNumberOfBytesToWrite,
    LPDWORD lpNumberOfBytesWritten,
    LPOVERLAPPED lpOverlapped
) {
    __asm {
        mov edi, edi
        push ebp
        mov ebp, esp
        mov ebx, jump
        jmp ebx
    }
}
BOOL WINAPI hookedWriteFile(
    HANDLE hFile,
    LPCVOID lpBuffer,
    DWORD nNumberOfBytesToWrite,
    LPDWORD lpNumberOfBytesWritten,
    LPOVERLAPPED lpOverlapped
) {
    char* bufferContent = new char[nNumberOfBytesToWrite];
    SIZE_T bytesRead;
    if (ReadProcessMemory(GetCurrentProcess(), lpBuffer, bufferContent, nNumberOfBytesToWrite, &bytesRead)) {
        
        FILE* file = fopen("output.txt", "ab");
        if (file == NULL) {
            return 1;
        }
        fwrite(bufferContent, bytesRead, 1, file);
        fclose(file);
    }
    delete[] bufferContent;
    //char* bufferContentB = new char[nNumberOfBytesToWrite];
    //memset(bufferContentB, 0, nNumberOfBytesToWrite);
    BOOL result = Transfer(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
    //delete[] bufferContentB;
    return result;
}
bool APIENTRY DllMain(HANDLE handle, DWORD dword, LPVOID lpvoid) {
    HMODULE hwnd = GetModuleHandle(TEXT("kernel32.dll"));
    DWORD base = (DWORD)GetProcAddress(hwnd, "WriteFile");
    DWORD oldProtect = 0;
    char message[256];
    sprintf_s(message, "CreateProcessA address: 0x%08X", base);
    MessageBoxA(NULL, message, "Information", MB_OK);
    if (VirtualProtect((LPVOID)base, 5, PAGE_EXECUTE_READWRITE, &oldProtect)) {
        DWORD value = (DWORD)hookedWriteFile - base - 5;
        jump = base + 5;
        __asm {
            mov eax, base
            mov byte ptr[eax], 0xe9
            inc eax
            mov ebx, value
            mov dword ptr[eax], ebx
        }
        VirtualProtect((LPVOID)base, 5, oldProtect, &oldProtect);
    }
    return true;
}


失败尝试的之一 这样后的output.txt全都是空格 

    char* bufferContentB = new char[nNumberOfBytesToWrite];
    memset(bufferContentB, 0, nNumberOfBytesToWrite);
    BOOL result = Transfer(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
    delete[] bufferContentB;


image.png



DLL注入器:

我一开始想着直接找chatgpt写一个,懒得去找这找那了,结果运行后发现弹出了注入成功,但是实际上并没有注入成功,主要是还没有任何报错,我就去全互联网寻了个遍,花费了大量时间,发现都没有用。

然后我看了一遍后,在想这个 "LoadLibraryW"为什么是W不是A或者空。然后我就去替换成了"LoadLibraryA",结果。。。就成功了。

“A” 后缀:代表 ANSI 版本。这个版本的函数使用单字节字符集,主要是 ASCII。例如,WNDCLASSA 是一个处理 ANSI 窗口类的结构。

“W” 后缀:代表 Unicode 版本。这个版本的函数使用双字节字符集,支持多种语言字符。例如,WNDCLASSW 是一个处理 Unicode 窗口类的结构。

我想起了之前我因为发现有些字符串会标红了,搜出来告诉我改成多字节集就行了 ,然后我一改,果然不标红了,没想到这个是个暗坑

image.png

#include <iostream>
#include <tchar.h>
#include <tlhelp32.h>
// 定义注入 DLL 的路径
PROCESS_INFORMATION pi;
BOOL InjectDLL(DWORD processID)
{
    // 获取目标进程的句柄
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
    if (hProcess == NULL) {
        MessageBox(NULL, L"Failed to open target process.", L"Error", MB_OK | MB_ICONERROR);
        return FALSE;
    }
    // 在目标进程中分配内存空间
    LPVOID pRemoteBuffer = VirtualAllocEx(hProcess, 0, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pRemoteBuffer == NULL) {
        MessageBox(NULL, L"Failed to allocate memory in target process.", L"Error", MB_OK | MB_ICONERROR);
        CloseHandle(hProcess);
        return FALSE;
    }
    LPCTSTR dllPath = L"CommandHook.dll"; // 替换为你的 DLL 路径
    // 将 DLL 路径写入目标进程
    if (!WriteProcessMemory(hProcess, pRemoteBuffer, (LPCVOID)dllPath, (_tcslen(dllPath) + 1) * sizeof(TCHAR), NULL)) {
        MessageBox(NULL, L"Failed to write DLL path into target process.", L"Error", MB_OK | MB_ICONERROR);
        VirtualFreeEx(hProcess, pRemoteBuffer, 0, MEM_RELEASE);
        CloseHandle(hProcess);
        return FALSE;
    }
    // 获取 LoadLibraryA 函数地址
    HMODULE hNtdll = LoadLibrary(L"kernel32.dll");
    if (!hNtdll)
    {
        CloseHandle(hProcess);
        return 0;
    }
    void* pLoadLibrary = nullptr;
    pLoadLibrary = GetProcAddress(hNtdll, "LoadLibraryW");
    if (pLoadLibrary == nullptr)
    {
        CloseHandle(hProcess);
        return 0;
    }
    DWORD dwThreadId = 0;
    HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, (LPVOID)pRemoteBuffer, 0, &dwThreadId);
    if (!hRemoteThread)
    {
        CloseHandle(hProcess);
        return 0;
    }
    //MessageBox(NULL, L"DLL injected successfully.", L"Success", MB_OK | MB_ICONINFORMATION);
    MessageBox(NULL, L"CommandHook.dll 注入成功", L"Success", MB_OK | MB_ICONINFORMATION);
    
    //printf("CommandHook.dll 注入成功");
    //getchar();
    //getchar();
    CloseHandle(hProcess);
    return TRUE;
}
int main(int argc, char* argv[])
{
    // 目标进程信息
    STARTUPINFOA si = { sizeof(si) };
    if (argv[1]==NULL) {
        printf("使用命令行: ./hook.exe 同目录需要破解的程序名");
        return false;
    }
    else {
        
        printf("正在注入程序名:: %s\n", argv[1]);
    }
    
    // 创建目标进程 "C:\\Users\\Administrator\\Desktop\\AAAAAAAAAAAA.exe"
    if (!CreateProcessA(argv[1], NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
        //MessageBox(NULL, L"Failed to create target process.", L"Error", MB_OK | MB_ICONERROR);
        printf("注入目标失败 请检查权限或文件名称" );
        return 1;
    }
    
    
    // 注入 DLL
    if (!InjectDLL(pi.dwProcessId)) {
        TerminateProcess(pi.hProcess, 1);
        return 1;
    }
    // 继续目标进程
    ResumeThread(pi.hThread);
    WaitForSingleObject(pi.hProcess, INFINITE);
    // 等待目标进程结束
    // 清理资源
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return 0;
}

注入程序需要使用 PowerShell(管理员) 或是通过赋予了管理员权限的cmd窗口 要不然无法注入成功



结语:

算是初步的实现了之前儿时的想法,这算是一个基本原理展示, 实际上这玩意不弄个GUI,不实现“把文件一拖然后点击运行后自动出结果”的话并不会比直接使用OD简便。

以前想到一个东西就立马去做了,现在还会想想做这个有没有什么意义,动力明显少了很多。


[修改于 4个月15天前 - 2024/07/08 20:59:42]

来自:计算机科学 / 软件综合动手实践:实验报导严肃内容:教程/课程
1
5
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
Treason
4个月2天前 IP:江西
934403

作者也学C++啊,加个好友吧


引用
评论(1)
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
章鱼wheat
进士 机友 笔友
文章
20
回复
290
学术分
0
2022/10/23注册,2分36秒前活动

年龄:2007-09-0* <h1 style="font-size: 150px;">大</h1> <h1 style="font-size: 10px;">小</h1> <div class="article-panel-count"><div class="fa fa-thumbs-up"></div><span>9999</span></div> <img src="XXXXXXXXXXXXXXXXXXXXXXXX:81/sticker/315491"> <button class="btn btn-primary">测试</button> <button class="m-b-05 m-r-05 btn-sm btn-default btn">测试</button> <a class="pointer" onclick="document.write('')">测试</a> <label><input type="checkbox" value="11"><span>测试</span></label>

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:江西
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}