首页 > 系统相关 >逆向工程核心原理——第二十七章 进程注入-代码注入

逆向工程核心原理——第二十七章 进程注入-代码注入

时间:2023-08-02 19:37:02浏览次数:45  
标签:逆向 GetLastError return 注入 printf FALSE NULL 第二十七章 hProcess

官方源码地址:

https://blog.kakaocdn.net/dn/buCuJU/btq2OpiKoTz/JIIGkCcw1xjLtsDt4yV5dk/%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C.zip?attach=1&knm=tfile.zip

虽然是韩语,但是编译依然ok!

 

写在前面,我用官方给的代码,使用vs2022编译release模式,在win11 上也注入成功了!

注意dll也需要编译!

逆向工程核心原理——第二十七章 进程注入-代码注入_Access

 

 

逆向工程核心原理——第二十七章 进程注入-代码注入_安全分析_02

 

 

sysmon数据的采集 我相信是和23章一样的,应该会有createremotethread的日志。不再复现。

 

 

代码注入

这里我们需要向notepad注入一段代码,从而达到弹出窗口的目的。


我们知道DLL注入,是要将我们想执行的代码,放入DLL中,在程序运行DLL时,运行我们想要执行的代码,而代码注入则不需要DLL文件,直接就可以执行。

代码注入练习:

首先使用process explorer查看已经运行的notepad的PID:

然后cmd打开我们写好的CodeInjection.exe,输入参数(notepad的PID)

接着就可以看到对话框弹出的:

CodeInjection.exe的代码如下,我使用的编译环境为 **VS2019 ** 运行环境为 Windows 7 x64

// CodeInjection.cpp  
// http://www.reversecore.com  

#include "windows.h"  
#include "stdio.h"  

typedef struct _THREAD_PARAM
{
    FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()  
    char    szBuf[4][128];          // "user32.dll", "MessageBoxA", "www.reversecore.com", "ReverseCore"  
} THREAD_PARAM, * PTHREAD_PARAM;

typedef HMODULE(WINAPI* PFLOADLIBRARYA)
(
    LPCSTR lpLibFileName
    );

typedef FARPROC(WINAPI* PFGETPROCADDRESS)
(
    HMODULE hModule,
    LPCSTR lpProcName
    );

typedef int (WINAPI* PFMESSAGEBOXA)
(
    HWND hWnd,
    LPCSTR lpText,
    LPCSTR lpCaption,
    UINT uType
    );

DWORD WINAPI ThreadProc(LPVOID lParam)
{
    PTHREAD_PARAM   pParam = (PTHREAD_PARAM)lParam;
    HMODULE         hMod = NULL;
    FARPROC         pFunc = NULL;

    // LoadLibrary()  
    hMod = ((PFLOADLIBRARYA)pParam->pFunc[0])(pParam->szBuf[0]);    // "user32.dll"  
    if (!hMod)
        return 1;

    // GetProcAddress()  
    pFunc = (FARPROC)((PFGETPROCADDRESS)pParam->pFunc[1])(hMod, pParam->szBuf[1]);  // "MessageBoxA"  
    if (!pFunc)
        return 1;

    // MessageBoxA()  
    ((PFMESSAGEBOXA)pFunc)(NULL, pParam->szBuf[2], pParam->szBuf[3], MB_OK);

    return 0;
}

BOOL InjectCode(DWORD dwPID)
{
    HMODULE         hMod = NULL;
    THREAD_PARAM    param = { 0, };
    HANDLE          hProcess = NULL;
    HANDLE          hThread = NULL;
    LPVOID          pRemoteBuf[2] = { 0, };
    DWORD           dwSize = 0;

    hMod = GetModuleHandleA("kernel32.dll");

    // set THREAD_PARAM  
    param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
    param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");
    strcpy_s(param.szBuf[0], "user32.dll");
    strcpy_s(param.szBuf[1], "MessageBoxA");
    strcpy_s(param.szBuf[2], "www.reversecore.com");
    strcpy_s(param.szBuf[3], "ReverseCore");

    // Open Process  
    if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS,   // dwDesiredAccess  
        FALSE,                // bInheritHandle  
        dwPID)))             // dwProcessId  
    {
        printf("OpenProcess() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    // Allocation for THREAD_PARAM  
    dwSize = sizeof(THREAD_PARAM);
    if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess,          // hProcess  
        NULL,                 // lpAddress  
        dwSize,               // dwSize  
        MEM_COMMIT,           // flAllocationType  
        PAGE_READWRITE)))    // flProtect  
    {
        printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    if (!WriteProcessMemory(hProcess,                       // hProcess  
        pRemoteBuf[0],                  // lpBaseAddress  
        (LPVOID)¶m,               // lpBuffer  
        dwSize,                         // nSize  
        NULL))                         // [out] lpNumberOfBytesWritten  
    {
        printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    // Allocation for ThreadProc()  
    dwSize = (DWORD)InjectCode - (DWORD)ThreadProc;
    if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess,          // hProcess  
        NULL,                 // lpAddress  
        dwSize,               // dwSize  
        MEM_COMMIT,           // flAllocationType  
        PAGE_EXECUTE_READWRITE)))    // flProtect  
    {
        printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    if (!WriteProcessMemory(hProcess,                       // hProcess  
        pRemoteBuf[1],                  // lpBaseAddress  
        (LPVOID)ThreadProc,             // lpBuffer  
        dwSize,                         // nSize  
        NULL))                         // [out] lpNumberOfBytesWritten  
    {
        printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    if (!(hThread = CreateRemoteThread(hProcess,            // hProcess  
        NULL,                // lpThreadAttributes  
        0,                   // dwStackSize  
        (LPTHREAD_START_ROUTINE)pRemoteBuf[1],     // dwStackSize  
        pRemoteBuf[0],       // lpParameter  
        0,                   // dwCreationFlags  
        NULL)))             // lpThreadId  
    {
        printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError());
        return FALSE;
    }

    WaitForSingleObject(hThread, INFINITE);

    CloseHandle(hThread);
    CloseHandle(hProcess);

    return TRUE;
}

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(),
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
        &hToken))
    {
        printf("OpenProcessToken error: %u\n", GetLastError());
        return FALSE;
    }

    if (!LookupPrivilegeValue(NULL,           // lookup privilege on local system  
        lpszPrivilege,  // privilege to lookup   
        &luid))        // receives LUID of privilege  
    {
        printf("LookupPrivilegeValue error: %u\n", GetLastError());
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    // Enable the privilege or disable all privileges.  
    if (!AdjustTokenPrivileges(hToken,
        FALSE,
        &tp,
        sizeof(TOKEN_PRIVILEGES),
        (PTOKEN_PRIVILEGES)NULL,
        (PDWORD)NULL))
    {
        printf("AdjustTokenPrivileges error: %u\n", GetLastError());
        return FALSE;
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        printf("The token does not have the specified privilege. \n");
        return FALSE;
    }

    return TRUE;
}

int main(int argc, char* argv[])
{
    DWORD dwPID = 0;

    if (argc != 2)
    {
        printf("\n USAGE  : %s <pid>\n", argv[0]);
        return 1;
    }

    // change privilege  
    if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
        return 1;

    // code injection  
    dwPID = (DWORD)atol(argv[1]);
    InjectCode(dwPID);

    return 0;
}

接下来我们使用OD找到ThreadProc()函数开始的位置

首先还是使用OD的附加(attach)功能,载入正在运行notepad:

按下F9,让notepad处于运行状态,在设置中将载入进程时断点打开:

这样,notepad载入新进程时就会被断下来,接着注入代码,就可以看到被断下来了:

 

 

标签:逆向,GetLastError,return,注入,printf,FALSE,NULL,第二十七章,hProcess
From: https://blog.51cto.com/u_11908275/6941754

相关文章

  • 进程注入如何通过调用栈,使用ML分类来检测——非常值得借鉴,待实践
    4、MachineLearningtoUltimatelyDefeatAdvancedRansomwareThreatsRSA2022的这个分享主题核心讲解了进程注入如何通过调用栈,使用ML分类来检测。当然,勒索的其他本质特征例如文件加密等没有提到。但是其进程注入的检测值得重点关注。Ryukasthemostadvancedformofransomw......
  • 进程注入检测 —— RtlCaptureStackBackTrace 获取当前函数的调用栈函数
    https://stackoverflow.com/questions/590160/how-to-log-stack-frames-with-windows-x64 https://cpp.hotexamples.com/examples/-/-/RtlCaptureStackBackTrace/cpp-rtlcapturestackbacktrace-function-examples.html  例子参考  平日里用VS开发工具在调时在Debug下有一个选......
  • 【逆向】x64程序逆向基础——调用约定和栈使用
    【逆向】x64程序逆向基础 主要区别1.所有地址指针都是64位。2.增加和扩展新的寄存器,并兼容原32位版本的通用寄存器。3.原指令指针寄存器EIP扩展为RIP。寄存器1.64位寄存器兼容原32位寄存器。2.新增加8个XMM寄存器(XMM8-XMM15)。3.扩展原32位寄存器的64位版本,并增加8个......
  • C++逆向分析——友元、内部类、命名空间和static
    友元友元可以理解为:朋友、元素;老师认为这个友元是C++中的一个垃圾,因为友元的存在破坏了面向对象的封装性,不推荐使用,之所以有这个章节是因为有人不了解这个概念。注意:在一些新版本的C++编译器里面已经不再提供类似于友元这样的特性了。大家都知道在C++中对象的私有成员,外部是无法访......
  • C++逆向分析——对象拷贝
    对象拷贝我们通常存储对象,都用数组、列表之类的来存储,那如下所示我们使用数组来存储对象,但是在工作中发现这个数组不够用了,就需要一个更大的数据,但我们重新创建一个数组还需要把原来的数据复制过来;在C语言中可以使用函数来进行拷贝,直接拷贝内存,在C++中实际上跟C语言要做的事情是一......
  • C++逆向分析——模版
    模版假设有一个冒泡排序的函数:voidSort(int*arr,intnLength){inti,k;for(i=0;i<nLength;i++){for(k=0;k<nLength-1-i;k++){if(arr[k]>arr[k+1]){inttemp=arr[k];arr[k]=arr[k+1];arr[k+1]=temp;}}}}但是这个冒......
  • C++逆向分析——运算符重载
    运算符重载现在有一个类,其中有一个函数用于比较2个类的成员大小:#include<stdio.h>classNumber{private:intx;inty;public:Number(intx,inty){this->x=x;this->y=y;}intMax(Number&n){returnthis->x>n.x&&this->y......
  • C++逆向分析——多态和虚表
    虚表上一章了解了多态,那么我们来了解一下多态在C++中是如何实现的。了解本质,那就通过反汇编代码去看就行了,首先我们看下非多态的情况下的反汇编代码:然后再来看下多态情况下的反汇编代码:很明显这里多态的情况下会根据edx间接调用,而非多态则会直接调用。那么我们来看下间接调用的流程......
  • C++逆向分析——继承与封装
    面向对象程序设计之继承与封装之前已经学习过继承和封装了,但是要在实际开发中使用,光学语法和原理是不够的,在设计层面我们需要做一些优化。如下代码是继承的例子:#include<stdio.h>classPerson{public:intAge;intSex;voidWork(){printf("Person:Work()"......
  • C++逆向分析——引用
    voidmain(){intx=1;int&ref=x;ref=2;printf("%d\n",ref);return;}反汇编代码:intx=1;00724A5FC745F401000000movdwordptr[x],1int&ref=x;00724A668D45F4lea......