[C++] 代码注入非dll版

前言

昨天完成了dll注入,今天就完成了代码注入,早知道这个,就应该早点这么做。

需要注意的问题

  • 64位程序只能注入64位目标程序,否则会告诉你访问错误(GetLastError() == 5)
  • 经过实际操作发现Release版本能正常注入,但是Debug版本不能(卡了好久,,,我太笨了)

DLL注入和代码注入区别

  • dll注入之后,dll就会一直在目标进程空间中,但是代码注入执行完成之后就消失了
  • 代码注入体积小,不占内存
  • 实际上我觉得可以再加一个,,,dll贼方便,,,不需要使劲考虑会不会变量地址错误的问题

代码

#include <windows.h>
#include <iostream>
#include <tlhelp32.h>

using namespace std;

// 用来传参的结构体
struct PARAM
{
    FARPROC func[2];    // LoadLibraryA() GetProcAddress()
    char cBuff[4][128]; // "User32.dll"、"MessageBox()"、"标题"、"内容"
};

// 定义三个函数指针(其实我理解来看就是制定了怎么格式化代码)
typedef HMODULE(*PLOADLIBRARYA)(LPCSTR);
typedef FARPROC(*PGETPROCADDRESS)(HMODULE,LPCSTR);
typedef int(*PMESSAGEBOXA)(int,LPCSTR,LPCSTR,int);  // 这里应该和MessageBoxA函数的参数列表一样,但是我这样也可以

// 通过进程名获取pid
DWORD GetPidByName(LPCWSTR lpName)
{
    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (!hSnap)
    {
        cout << "创建进程快照失败" << endl;
        return 0;
    }
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);
    Process32First(hSnap, &pe);
    do
    {
        if (!_wcsicmp(lpName, pe.szExeFile))
        {
            return pe.th32ProcessID;
        }
    } while (Process32Next(hSnap, &pe));
    return 0;
}

// 即将注入到目标进程的细作 写的这么麻烦完全是因为代码注入不能使用自己程序的资源,
// 下面用到的变量资源完全在目标进程空间
DWORD WINAPI ThreadProc(LPVOID lParam)
{
    PARAM* s = (PARAM*)lParam;                                          // 强转参数
    HMODULE hmMod = ((PLOADLIBRARYA)s->func[0])(s->cBuff[0]);         // 实际上是LoadLibraryA()
    FARPROC pFunc = ((PGETPROCADDRESS)s->func[1])(hmMod, s->cBuff[1]);    // 实际上是GetProcAddress()
    ((PMESSAGEBOXA)pFunc)(NULL, s->cBuff[2], s->cBuff[3], 0);         // 实际上是MessageBoxA
    return 0;
}

// 提权
int EnableDebugPrivilege()
{
    HANDLE token;
    TOKEN_PRIVILEGES tp;
    // 打开进程令牌环
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
    {
        cout << "打开进程令牌失败" << endl;
        return 0;
    }
    //  获取进程本地唯一ID
    LUID luid;
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid))
    {
        cout << "获取LUID失败" << endl;
        return 0;
    }
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    tp.Privileges[0].Luid = luid;
    // 调整进程权限
    if (!AdjustTokenPrivileges(token, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        cout << "提权失败" << endl;
        return 0;
    }
    return 1;
}

int main()
{
    cout << "ThreadProc地址: "<<ThreadProc << endl;
    if (!EnableDebugPrivilege())
    {
        cout << "提权失败" << endl;
        return 0;
    }
    DWORD dwTargetPid = GetPidByName(L"notepad.exe");
    if (!dwTargetPid)
    {
        cout << "获取PID失败" << endl;
        return 0;
    }
    cout << "PID: " << dwTargetPid << endl;

    // 打开进程
    HANDLE hTarget = OpenProcess(PROCESS_ALL_ACCESS, false, dwTargetPid);
    if (!hTarget)
    {
        cout << "打开进程失败" << GetLastError() << endl;
        return 0;
    }

    PARAM p;
    p.func[0] = (FARPROC)LoadLibraryA;  // 因为本进程已经加载了这个函数所在的模块 kernel32.dll 所以能直接得到地址
    p.func[1] = (FARPROC)GetProcAddress;// 这两个在目标进程中地址也是这个,所以能直接用

    // 填充参数
    strcpy_s(p.cBuff[0],"User32.dll");  
    strcpy_s(p.cBuff[1],"MessageBoxA");
    strcpy_s(p.cBuff[2],"我是细作二号,多多指教 By Startu");
    strcpy_s(p.cBuff[3],"你好,");

    void* pParam = nullptr;
    pParam = VirtualAllocEx(hTarget, 0, sizeof(p), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (pParam == nullptr)
    {
        cout << "申请参数所需内存失败" << endl;
        return 0;
    }

    if (!WriteProcessMemory(hTarget, pParam, (LPCVOID)&p, sizeof(p), NULL))
    {
        cout << "写入参数失败" << endl;
        return 0;
    }

    void* pFunc = nullptr;
    //DWORD dwFuncSize = (DWORD)ThreadProc - (DWORD)EnableDebugPrivilege;
    DWORD dwFuncSize = 4096;    // 写死函数大小,在Debug模式下,上面注释的代码会得到错误的结果
    cout << "函数大小: "<<dwFuncSize << endl;
    pFunc = VirtualAllocEx(hTarget,0, dwFuncSize,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
    if (pFunc == nullptr)
    {
        cout << "申请函数内存失败" << endl;
        CloseHandle(hTarget);
        return 0;
    }

    if (!WriteProcessMemory(hTarget, pFunc, (LPCVOID)ThreadProc, dwFuncSize, NULL))
    {
        cout << "写入函数代码失败" << endl;
        CloseHandle(hTarget);
        return 0;
    }

    cout << "函数地址: " << pFunc << endl;
    DWORD dwThreadId = 0;
    HANDLE hRemoteThread = CreateRemoteThread(hTarget, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)pParam, 0, &dwThreadId);
    if (!hRemoteThread)
    {
        cout << "创建进程失败" << endl;
        CloseHandle(hTarget);
        return 0;
    }
    WaitForSingleObject(hRemoteThread,INFINITE);        // 等待注入线程结束
    cout << "运行结束" << hRemoteThread << endl;
    CloseHandle(hTarget);
    return 0;
}
  • 运行之后,就能喜闻乐见的见到下面的结果了

[C++] 代码注入非dll版

通过x64dbg可以代码确实注入到notepad里面了 撒花★,°:.☆( ̄▽ ̄)/$:.°★

解决问题过程

前面解决这个问题想了好久(笨死,,)

后来师傅说可以试试windbg调试一下试试,但是windbg是真的很难操作。。。

后来想到了OD,不过OD不能调试64位程序,幸好在两年前了解到了x64dbg,这个是个好工具,我觉得完全可以接下OD的旗帜。

  • 这里 https://github.com/x64dbg/x64dbg/releases下载到x64dbg
  • 然后打开记事本,使用dbg附加进程,点击选项选项然后选择在线程入口下暂停
    • [C++] 代码注入非dll版
    • OD设置位置也是这里
  • 多点几次运行按钮,让notepad自己的线程先跑起来
  • 然后打开代码开始注入,成功之后dbg会暂停的,一般来说就能看到下图中代码,也即是注入进去的线程函数
  • F8步过,看到传参那部分没有问题,然后再call的时候(MessageBox函数),报错了,下面提示说不合法的访问(EXCEPTION_ACCESS_VIOLATION),突然想起来,应该是这里的指针指向了不合法的地址。

[C++] 代码注入非dll版

  • 检查代码之后,确认参数地址都没问题,但是我直接在线程函数中调用了MessageBoxA(),这个应该就是问题的关键,一直没想到的原因,就是因为别的博文中说,“线程函数中,不可以使用Kernel32.dll和user32.dll之外的函数”,,,我理解成了,MessageBoxA是User32.dll里面的函数,所以应该可以直接使用。😔

  • 那么接下来就改造一下代码,把函数也给写入进去,在线程中载入模块。也就变成了上面的成品代码。

  • 但是依旧不行,还是会闪退,,,再通过dbg看了发现错误不一样了,他是这样的了

    • [C++] 代码注入非dll版
  • 似乎没有看到具体代码,全是jmp,然后通过vs的汇编窗口,我看到这了

    • [C++] 代码注入非dll版
  • 这里是所有的函数,似乎是一个目录,我通过代码中的方式获取到的地址实际上只是个jmp,注入的只是这个jmp,然后线程中,jmp了不合法的地址,就错了。

  • 最终调成Release模式之后,就能成功运行了。这么看来 Release模式下,似乎是没有这个目录的。但是这个目录是什么还是不太清楚,了解的伙伴麻烦留个言。

参考

参考:https://www.cnblogs.com/2f28/p/9974552.html

谢谢~~

原文链接: https://www.cnblogs.com/cjdty/p/13182442.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    [C++] 代码注入非dll版

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/358051

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午12:05
下一篇 2023年3月2日 下午12:06

相关推荐