SetThreadContext注入DLL

注入DLL的方式有很多

R3就有远程线程CreateRemoteThread、SetWindowsHookEx、QueueUserApc、SetThreadContext

R0可以参考sudami大神的思路

关于本文32位下参考

http://bbs.pediy.com/showthread.php?t=181174&highlight=setthreadContext+dll+%E6%B3%A8%E5%85%A5

言归正传

大体思路就是

我们先打开目标进程,枚举目标线程采用的是系统快照的方式,比较线程所属的进程是否是我们的目标进程,SuspendThread挂起线程,GetThreadContext获得eip/rip,在目标进程空间写入Shellcode,SetThreadContext将eip/rip设置为我们shellcode的地址,shellcode执行load dll的工作,最后跳转回之前的eip继续执行。

我们先说说32位的

shellcode为

BYTE ShellCode[64]=
{
    0x60,
    0x9c,
    0x68,               //push
    0xaa,0xbb,0xcc,0xdd,//dll path  +3  dll最目标进程中的地址
    0xff,0x15,          //call     这里感觉有点乱,我在64下直接call 相对地址
    0xdd,0xcc,0xbb,0xaa,//+9 LoadLibrary Addr  Addr
    0x9d,
    0x61,
    0xff,0x25,          //jmp
    0xaa,0xbb,0xcc,0xdd,// +17  jmp  eip
    0xaa,0xaa,0xaa,0xaa,// loadlibrary addr
    0xaa,0xaa,0xaa,0xaa//  jmpaddr  +25

    //  +29
}; 

这是一个需要我们填充的shellcode

    strcpy((char*)DllPath,"D:\\Dllx86.dll");//这里是要注入的DLL名字
    *(DWORD*)(ShellCode+3)=(DWORD)LpAddr+29;
    ////////////////
    *(DWORD*)(ShellCode+21)=LoadDllAAddr;   //loadlibrary地址放入shellcode中
    *(DWORD*)(ShellCode+9)=(DWORD)LpAddr+21;//修改call 之后的地址 为目标空间存放 loaddlladdr的地址
    //////////////////////////////////
    *(DWORD*)(ShellCode+25)=ctx.Eip;
    *(DWORD*)(ShellCode+17)=(DWORD)LpAddr+25;//修改jmp 之后为原来eip的地址

最后翻译成汇编

/*
{
00973689 >    60                PUSHAD
0097368A      9C                PUSHFD
0097368B      68 50369700       PUSH notepad.00973650
00973690      FF15 70369700     CALL DWORD PTR DS:[973670]
00973696      9D                POPFD
00973697      61                POPAD
00973698    - FF25 30369700     JMP DWORD PTR DS:[973630]
}
*/

然后需要注意的是 操作之前要 挂起, 结束后一定要 恢复,32位比较简单

我们在看看64位的shellcode

BYTE ShellCode64[64]=
{
    0x48,0x83,0xEC,0x28,  // sub rsp ,28h

    0x48,0x8D,0x0d,       // [+4] lea rcx,
    0xaa,0xbb,0xcc,0xdd,  // [+7] dll path offset =  TargetAddress- Current(0x48)[+4] -7 

    0xe8,                 // [+11]
    0xdd,0xcc,0xbb,0xaa,  // [+12] call LoadLibrary offset = TargetAddress - Current(0xe8)[+11] -5

    0x48,0x83,0xc4,0x28,  // [+16] add rsp,28h
    //0xcc, 调试时断下来的int 3 正常运行的时候非常傻逼的没有清掉...难怪一直死
    0xff,0x25,            // [+20]
    0xaa,0xbb,0xcc,0xdd,  // [+22] jmp rip offset  = TargetAddress - Current(0xff)[+20] - 6

    0xaa,0xbb,0xcc,0xdd,  //+26
    0xaa,0xbb,0xcc,0xdd
    //+34
};

64位下,寻址都是相对寻址,函数调用参数传递是rcx,rdx,r8,r9,超过4参数采用栈传递

首先需要sub rsp,28h

rsp我本来是只有一个参数+返回地址 应该是 8*2 ,可是用10h 不能正常运行, 故还是用的5*8 = 28h 4个寄存器+返回地址

然后将dll名称地址给rcx

在调用loadlibrary,最后跳回rip

    DllPath=ShellCode64+34;
    strcpy((char*)DllPath,"D:\\Dll.dll");//这里是要注入的DLL名字
    DWORD DllNameOffset = 23;// ((BYTE*)LpAddr+34) -((BYTE*)LpAddr+4) -7 这个指令7个字节
    *(DWORD*)(ShellCode64+7)=(DWORD)DllNameOffset;
    ////////////////
    DWORD LoadDllAddroffset = (BYTE*)LoadDllAAddr - ((BYTE*)LpAddr + 11) -5;  //这个指令5个字节e8 + 4addroffset
    *(DWORD*)(ShellCode64+12)=LoadDllAddroffset;
    //////////////////////////////////

    *(DWORD64*)(ShellCode64+26)=ctx.Rip; //64下为rip
    *(DWORD*)(ShellCode64+22)= (DWORD)0; //我将地址放在+26的地方,相对offset为0

//  这里因为这样写跳转不到目标地址,故x64 应该要中转一次  相对寻址
//     DWORD Ds = (DWORD)ctx.SegDs;
//     DWORD RipOffset = (BYTE*)ctx.Rip - ((BYTE*)LpAddr+20) -6;
//     *(DWORD*)(ShellCode64+22)=(DWORD)ctx.Rip;

完整代码:

#include "stdafx.h"

#include <iostream>
using namespace std;
#include <windows.h>
#include "tlhelp32.h"
BYTE ShellCode[64]=
{
    0x60,
    0x9c,
    0x68,               //push
    0xaa,0xbb,0xcc,0xdd,//dll path  +3  dll最目标进程中的地址
    0xff,0x15,          //call     这里感觉有点乱,我在64下直接call 相对地址
    0xdd,0xcc,0xbb,0xaa,//+9 LoadLibrary Addr  Addr
    0x9d,
    0x61,
    0xff,0x25,          //jmp
    0xaa,0xbb,0xcc,0xdd,// +17  jmp  eip
    0xaa,0xaa,0xaa,0xaa,// loadlibrary addr
    0xaa,0xaa,0xaa,0xaa//  jmpaddr  +25

    //  +29
}; 

/*
{
00973689 >    60                PUSHAD
0097368A      9C                PUSHFD
0097368B      68 50369700       PUSH notepad.00973650
00973690      FF15 70369700     CALL DWORD PTR DS:[973670]
00973696      9D                POPFD
00973697      61                POPAD
00973698    - FF25 30369700     JMP DWORD PTR DS:[973630]
}
*/

BYTE ShellCode64[64]=
{
    0x48,0x83,0xEC,0x28,  // sub rsp ,28h

    0x48,0x8D,0x0d,       // [+4] lea rcx,
    0xaa,0xbb,0xcc,0xdd,  // [+7] dll path offset =  TargetAddress- Current(0x48)[+4] -7 

    0xe8,                 // [+11]
    0xdd,0xcc,0xbb,0xaa,  // [+12] call LoadLibrary offset = TargetAddress - Current(0xe8)[+11] -5

    0x48,0x83,0xc4,0x28,  // [+16] add rsp,28h
    //0xcc, 调试时断下来的int 3 正常运行的时候非常傻逼的没有请掉...难怪一直死
    0xff,0x25,            // [+20]
    0xaa,0xbb,0xcc,0xdd,  // [+22] jmp rip offset  = TargetAddress - Current(0xff)[+20] - 6

    0xaa,0xbb,0xcc,0xdd,  //+26
    0xaa,0xbb,0xcc,0xdd
    //+34
};
BOOL EnableDebugPriv() ;
BOOL StartHook(HANDLE hProcess,HANDLE hThread);

int _tmain(int argc, _TCHAR* argv[])
{

    EnableDebugPriv() ;
    int ProcessId = 0;
    cin>>ProcessId;

    HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS,NULL,ProcessId);

    // 定义线程信息结构
    THREADENTRY32 te32 = {sizeof(THREADENTRY32)} ;
    //创建系统线程快照  ss
    HANDLE hThreadSnap = CreateToolhelp32Snapshot ( TH32CS_SNAPTHREAD, 0 ) ;
    if ( hThreadSnap == INVALID_HANDLE_VALUE )
        return FALSE ;  

    // 循环枚举线程信息
    if ( Thread32First ( hThreadSnap, &te32 ) )
    {
        do{  

            if(te32.th32OwnerProcessID == ProcessId)
            {
                HANDLE Thread = OpenThread(THREAD_ALL_ACCESS,NULL,te32.th32ThreadID);

                SuspendThread(Thread);
                if (!StartHook(Process,Thread))
                {
                    TerminateProcess(Process,0);
                    printf("失败\n");
                    getchar();
                    return 0;
                }
                CloseHandle(Process);
                CloseHandle(Thread);

            }

        }while ( Thread32Next ( hThreadSnap, &te32 ) ) ;
    }  

    CloseHandle ( hThreadSnap ) ;
}

BYTE *DllPath;
BOOL StartHook(HANDLE hProcess,HANDLE hThread)
{

#ifdef _WIN64 

    CONTEXT ctx;
    ctx.ContextFlags=CONTEXT_ALL;
    if (!GetThreadContext(hThread,&ctx))
    {
        printf("GetThreadContext Error\n");
        return FALSE;
    }
    LPVOID LpAddr=VirtualAllocEx(hProcess,NULL,64,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (LpAddr==NULL)
    {
        printf("VirtualAlloc Error\n");
        return FALSE;
    }
    DWORD64 LoadDllAAddr=(DWORD64)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryA");
    if (LoadDllAAddr==NULL)
    {
        printf("LoadDllAddr error\n");
        return FALSE;
    }
    /*

    0x48,0x83,0xEC,0x28,  //sub rsp ,28h

    0x48,0x8D,0x0d,       // [+4] lea rcx,
    0xaa,0xbb,0xcc,0xdd,  // [+7] dll path offset =  TargetAddress- Current(0x48)[+4] -7 

    0xe8,                 // [+11]
    0xdd,0xcc,0xbb,0xaa,  // [+12] call LoadLibrary offset = TargetAddress - Current(0xe8)[+11] -5

    0x48,0x83,0xc4,0x28,  // [+16] add rsp,28h

    0xff,0x25,            // [+20]
    0xaa,0xbb,0xcc,0xdd,  // [+22] jmp rip offset  = TargetAddress - Current(0xff)[+20] - 6

    0xaa,0xbb,0xcc,0xdd,  //+26
    0xaa,0xbb,0xcc,0xdd
    //+34
    */
    DllPath=ShellCode64+34;
    strcpy((char*)DllPath,"D:\\Dll.dll");//这里是要注入的DLL名字
    DWORD DllNameOffset = 23;// ((BYTE*)LpAddr+34) -((BYTE*)LpAddr+4) -7 这个指令7个字节
    *(DWORD*)(ShellCode64+7)=(DWORD)DllNameOffset;
    ////////////////
    DWORD LoadDllAddroffset = (BYTE*)LoadDllAAddr - ((BYTE*)LpAddr + 11) -5;  //这个指令5个字节e8 + 4addroffset
    *(DWORD*)(ShellCode64+12)=LoadDllAddroffset;
    //////////////////////////////////

    *(DWORD64*)(ShellCode64+26)=ctx.Rip; //64下为rip
    *(DWORD*)(ShellCode64+22)= (DWORD)0; //我将地址放在+26的地方,相对offset为0

//  这里因为这样写跳转不到目标地址,故x64 应该要中转一次  相对寻址
//     DWORD Ds = (DWORD)ctx.SegDs;
//     DWORD RipOffset = (BYTE*)ctx.Rip - ((BYTE*)LpAddr+20) -6;
//     *(DWORD*)(ShellCode64+22)=(DWORD)ctx.Rip;

    ////////////////////////////////////
    if (!WriteProcessMemory(hProcess,LpAddr,ShellCode64,64,NULL))
    {
        printf("write Process Error\n");
        return FALSE;
    }
    ctx.Rip=(DWORD64)LpAddr;
    if (!SetThreadContext(hThread,&ctx))
    {
        printf("set thread context error\n");
        return FALSE;
    }
    ResumeThread(hThread);
    return TRUE;

#else
    CONTEXT ctx = {0};
    ctx.ContextFlags=CONTEXT_ALL;
    if (!GetThreadContext(hThread,&ctx))
    {
        int a = GetLastError();
        printf("GetThreadContext Error\n");
        return FALSE;
    }
    LPVOID LpAddr=VirtualAllocEx(hProcess,NULL,64,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    if (LpAddr==NULL)
    {
        printf("VirtualAlloc Error\n");
        return FALSE;
    }
    DWORD LoadDllAAddr=(DWORD)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryA");
    if (LoadDllAAddr==NULL)
    {
        printf("LoadDllAddr error\n");
        return FALSE;
    }

    /////////////
    /*
    0x60,              PUSHAD
    0x9c,              PUSHFD
    0x68,              PUSH
    0xaa,0xbb,0xcc,0xdd,//dll path  address
    0xff,0x15,            CALL
    0xdd,0xcc,0xbb,0xaa,  offset
    0x9d,                  POPFD
    0x61,                  POPAD
    0xff,0x25,             JMP
    0xaa,0xbb,0xcc,0xdd,//  [xxxxx]
    0xaa,0xaa,0xaa,0xaa,// LoadLibrary Address
    0xaa,0xaa,0xaa,0xaa//  恢复的EIP  Address
                         // +29  Dll名字
    */
    _asm mov esp,esp
    DllPath=ShellCode+29;
    strcpy((char*)DllPath,"D:\\Dllx86.dll");//这里是要注入的DLL名字
    *(DWORD*)(ShellCode+3)=(DWORD)LpAddr+29;
    ////////////////
    *(DWORD*)(ShellCode+21)=LoadDllAAddr;   //loadlibrary地址放入shellcode中
    *(DWORD*)(ShellCode+9)=(DWORD)LpAddr+21;//修改call 之后的地址 为目标空间存放 loaddlladdr的地址
    //////////////////////////////////
    *(DWORD*)(ShellCode+25)=ctx.Eip;
    *(DWORD*)(ShellCode+17)=(DWORD)LpAddr+25;//修改jmp 之后为原来eip的地址
    ////////////////////////////////////
    if (!WriteProcessMemory(hProcess,LpAddr,ShellCode,64,NULL))
    {
        printf("write Process Error\n");
        return FALSE;
    }
    ctx.Eip=(DWORD)LpAddr;
    if (!SetThreadContext(hThread,&ctx))
    {
        printf("set thread context error\n");
        return FALSE;
    }
    ResumeThread(hThread);
    return TRUE;
#endif

};

BOOL EnableDebugPriv()
{
    HANDLE   hToken;
    LUID   sedebugnameValue;
    TOKEN_PRIVILEGES   tkp;
    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
    {
        return   FALSE;
    } 

    if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&sedebugnameValue))
    {
        CloseHandle(hToken);
        return   FALSE;
    }
    tkp.PrivilegeCount   =   1;
    tkp.Privileges[0].Luid   =   sedebugnameValue;
    tkp.Privileges[0].Attributes   =   SE_PRIVILEGE_ENABLED; 

    if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,NULL))
    {
        return   FALSE;
    }
    CloseHandle(hToken);
    return TRUE;

} 

这个小demo时学到比较多的,首先32位的很早就成功了,之前弄64的时候shellcode一直不对,然后今天试着先用内联汇编写64位的这个程序

IncludeLib User32.Lib
;导入定义
EXTERN LoadLibraryA:PROC

;初始化数据定义
.DATA
szPath     BYTE  "D:\\Dll.dll",0

.CODE
  FUNC PROC
  sub rsp,28H     ;分配堆栈,四个参数+返回值,十进制40(5*8)为16进制28H
  lea rcx,szPath  ;消息文本
  call LoadLibraryA ;调用消息函数
  add rsp,28H      ;平衡堆栈,四个参数+返回值,十进制40为16进制28H
  ret
  FUNC ENDP
 END
// HelloPE.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<windows.h>

extern "C" int _cdecl FUNC();

int _tmain(int argc, _TCHAR* argv[])
{

    //LoadLibraryA("D:\\Dll.dll");
    int a  = 3;
    int b  = 4;
    int c = FUNC();
    printf("%d",c);
    return 0;
}

可是看不到机器码,也是不行

然后用windbg神器Attach这个程序

然后就看到机器码如下

HelloPE!FUNC:
00000001`3f5a1090 4883ec28        sub     rsp,28h
00000001`3f5a1094 488d0d877f0000  lea     rcx,[HelloPE!szPath (00000001`3f5a9022)]
00000001`3f5a109b e80a000000      call    HelloPE!LoadLibraryA (00000001`3f5a10aa)
00000001`3f5a10a0 4883c428        add     rsp,28h
00000001`3f5a10a4 c3              ret
00000001`3f5a10a5 cc              int     3
00000001`3f5a10a6 cc              int     3
00000001`3f5a10a7 cc              int     3
00000001`3f5a10a8 cc              int     3
00000001`3f5a10a9 cc              int     3

HelloPE!LoadLibraryA:
00000001`3f5a10aa ff25d8a20000    jmp     qword ptr [HelloPE!_imp_LoadLibraryA (00000001`3f5ab388)]

然后就字节构造机器码,调啊调就成功了

所以不会的还是要自己多研究,研究研究就有了~

时间: 2024-10-12 21:31:38

SetThreadContext注入DLL的相关文章

创建进程时注入DLL

#include "stdafx.h" #include <Windows.h> // 函数声明 typedef BOOL (WINAPI* Proc_CreateProcessW)(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInherit

Windows x86/ x64 Ring3层注入Dll总结

0x01.前言 提到Dll的注入,立马能够想到的方法就有很多,比如利用远程线程.Apc等等,这里我对Ring3层的Dll注入学习做一个总结吧. 我把注入的方法分成六类,分别是:1.创建新线程.2.设置线程上下背景文,修改寄存器.3.插入Apc队列.4.修改注册表.5.挂钩窗口消息.6.远程手动实现LoadLibrary. 那么下面就开始学习之旅吧! 0x02.预备工作 在涉及到注入的程序中,提升程序的权限自然是必不可少的,这里我提供了两个封装的函数,都可以用于提权.第一个是通过权限令牌来调整权限

N种内核注入DLL的思路及实现

内核注入,技术古老但很实用.现在部分RK趋向无进程,玩的是SYS+DLL,有的无文件,全部存在于内存中.可能有部分人会说:"都进内核了.什么不能干?".是啊,要是内核中可以做包括R3上所有能做的事,软件开发商们也没必要做应用程序了.有时,我们确实需要R3程序去干驱动做起来很困难或者没必要驱动中去做的事,进程 /  DLL是不错的选择,但进程目标太大,所以更多的同学趋向于注DLL.     若要开发安全软件.小型工具,可借鉴其思路,Anti Rootkits时,在某些极端情况下,可使用同

[转]N种内核注入DLL的思路及实现

内核注入,技术古老但很实用.现在部分RK趋向无进程,玩的是SYS+DLL,有的无文件,全部存在于内存中.可能有部分人会说:“都进内核了.什么不能干?”.是啊,要是内核中可以做包括R3上所有能做的事,软件开发商们也没必要做应用程序了.有时,我们确实需要R3程序去干驱动做起来很困难或者没必要驱动中去做的事,进程 /  DLL是不错的选择,但进程目标太大,所以更多的同学趋向于注DLL.     若要开发安全软件.小型工具,可借鉴其思路,Anti Rootkits时,在某些极端情况下,可使用同样的技术发

注入 - 远线程注入DLL到目标进程

// // 函数 -- void InjectDLL(LPCTSTR) // // 功能 -- 注入DLL到指定窗口 // // @param -- 要注入的DLL全路径 // // 返回值 -- 无 // void InjectDLL(LPCTSTR lpDLLFullPath) { DWORD dwPID = 0; // 目标进程PID HANDLE hGameProcess = NULL; // 目标进程句柄 LPDWORD lpdwAddr = NULL; // 远程申请的内存空间地址

远程创建线程注入DLL

HANDLE WINAPI CreateRemoteThread(__in HANDLE hProcess,__in LPSECURITY_ATTRIBUTES lpThreadAttributes,__in SIZE_T dwStackSize,__in LPTHREAD_START_ROUTINE lpStartAddress,__in LPVOID lpParameter,__in DWORD dwCreationFlags,__out LPDWORD lpThreadId);hProce

【windows核心编程】使用远程线程注入DLL

前言 该技术是指通过在[目标进程]中创建一个[远程线程]来达到注入的目的. 创建的[远程线程]函数为LoadLibrary, 线程函数的参数为DLL名字, 想要做的工作在DLL中编写.  示意图如下:  相关API 1.创建远程线程 //该函数除了第一个参数为目标进程句柄外 //其他参数均和CreateThread一样 HANDLE hThread = CreateRemoteThread( __in HANDLE hProcess, //目标进程句柄 __in_opt LPSECURITY_A

远程线程注入dll

// CommonInject.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <WinUser.h> #include <WinDef.h> #include <iostream> #include <Tlhelp32.h> using namespa

Windows挂钩注入DLL

注入DLL实现源码:HINSTANCE g_hInstDll = NULL; HHOOK g_hHook = NULL; DWORD g_dwThreadId = 0; #ifdef _MANAGED #pragma managed(push, off) #endif BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call)