windows下32位汇编代码注入

以前写的那个dll注入在技术对抗中是比较容易检测的,因为你要加载dll,对方只要遍历一下dll,或者dll个数检测一下,有问题直接退出程序,而汇编代码注入就不一样,这是直接把代码写到内存中,检测内存难度可比检测dll要难的,而且你也可以利用内存对齐把代码写到因对齐而空闲的内存中,反正这些靠自己去想吧,原理就是在内存中注入代码,至于在哪个内存地址写就看自己想象了

注入原理:利用win32 api的VirtualAllocEx在目标进程开辟一块内存空间,用api—VirtualProtect修改一下内存属性,把自己的二进制代码利用api–WriteProcessMemory写进目标进程中,在利用api—CreateRemoteThread在目标进程中创建一个线程去执行这段内存的代码
**注意点:**一般进程都会加载ntdll,kernel32.dll也有可能加载,user32.dll,我选择的是调用user32.dll中的messagebox,所以要如果要所有的目标程序都支持你的注入程序(注入程序具有通用性)就要在注入的时候,让目标程序加载一下user32.dll,
遍历一下目标进程的模块(有api遍历模块),查找是否有user32.dll,如果没有让目标进程加载user32.dll
目标进程加载user32.dll思路有两种:一种就是我上次写的dll注入,就在目标进程开辟一块内存,内存中存放user32.dll字符串做参数,然后获取kerner32.dll中的LoadLibrary函数地址,利用创建远程线程去执行LoadLibrary函数(如果不成功说明自己kernel32.dll和目标的kernel32版本不一样,或者api地址不一样,这时候就要做地址重定位,利用偏移去定位地址)
第二种就是我们现在写的这种,用注入汇编代码调用api,这种方式看下列代码就清楚了

两种写法注入

1用纯32位汇编写代码
用radAsm创建一个窗口程序,点击按钮进行注入代码,代码如下
injection.inc


include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

DlgProc			PROTO	:HWND,:UINT,:WPARAM,:LPARAM

IDD_DIALOG1			equ 101
IDB_INJECT      EQU 1001

.const
  g_WindowName db "计算器", 0
  g_ClassName  db "SciCalc", 0
  g_User32     db "user32.dll", 0
  g_MessageBox    db "MessageBoxA", 0

;#########################################################################

.data?

hInstance			dd ?

injection.asm

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include Inject.inc

.code

InjectCode:
  ;loadlibrary "user32.dll"
  ;参数入栈,参数从右往左入栈
  push 00646c72h
  push 6f57206fh
  push 6c6c6568h
  mov  ebx, esp
  push 00000065h
  push 6c746954h
  mov ecx, esp
  push MB_OK
  push ecx
  push ebx
  push NULL
LABEL1:
  mov  eax, 12345678h   ;12345678只是为了开辟一块内存好放api实际的地址,注入代码前会把这片内存进行api地址重定位
  call eax
  add  esp, 20
  retn  4   ;创建的远程线程的函数的参数默认值0平栈

Inject proc
  LOCAL @hWnd:HWND
  LOCAL @dwPID:DWORD
  LOCAL @hProcess:HANDLE
  LOCAL @pBuff:PVOID
  LOCAL @dwNumber:DWORD 
  LOCAL @hThread:DWORD 
  LOCAL @hUser32:DWORD 
  LOCAL @pfnMsgBox:DWORD 
  LOCAL @dwOld:DWORD 
    
  ;远程线程注入
  ;1.FindWindow
  invoke FindWindow, offset g_ClassName, NULL
  .if eax == NULL
    ret
  .endif
  mov @hWnd, eax
  
  ;2.获取进程pid
  invoke GetWindowThreadProcessId, @hWnd, addr @dwPID 
  
  ;3.打开进程
  invoke OpenProcess,PROCESS_ALL_ACCESS, FALSE, @dwPID
  .if eax == NULL
    ret
  .endif
  mov @hProcess, eax
  
  ;4.远程申请内存
  invoke VirtualAllocEx,@hProcess, NULL, 1000h, MEM_COMMIT, PAGE_EXECUTE_READWRITE
  .if eax == NULL
    jmp  SAFE_EXIT
  .endif
  mov @pBuff, eax
  
  ;修改内存保护属性,这是修改自己内存属性的版本,EX版本是修改目标内存属性的
  invoke VirtualProtectEx,@hProcess,offset InjectCode, 1000h, PAGE_EXECUTE_READWRITE, addr @dwOld
  ;这里可以加遍历模块列表进行判断是否有user32.dll,没有就加载,我只是写一个简单的demo
  ;API地址重定位
  invoke GetModuleHandle, offset g_User32
  mov @hUser32, eax
  invoke GetProcAddress,@hUser32, offset g_MessageBox
  mov @pfnMsgBox, eax
  mov esi, @hUser32
  sub eax, esi  ;offset
  add eax, esi  ;+base  
  mov ebx, offset LABEL1
  mov dword ptr [ebx+1], eax
  
  
  ;5.写入代码
  invoke WriteProcessMemory,@hProcess, 
                            @pBuff, 
                            offset InjectCode, 
                            offset Inject - offset InjectCode, 
                            addr @dwNumber
  .if !eax
    jmp   SAFE_EXIT
  .endif
                            
  
  
  ;6.创建远程线程
  invoke CreateRemoteThread,@hProcess, NULL, 0, @pBuff, NULL, 0, NULL
  .if eax == NULL
    jmp   SAFE_EXIT
  .endif
  mov @hThread, eax
  
SAFE_EXIT: 
  .if @hThread != NULL
    invoke CloseHandle, @hThread
  .endif
  
  .if @hProcess != NULL
    invoke CloseHandle,@hProcess
  .endif
  
  ret

Inject endp

start:

	invoke GetModuleHandle,NULL
	mov		hInstance,eax

  invoke InitCommonControls
	invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
	invoke ExitProcess,0

;########################################################################

DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

	mov		eax,uMsg
	.if eax==WM_INITDIALOG

	.elseif eax==WM_COMMAND
    mov eax, wParam
    .if ax == IDB_INJECT;如果点击按钮就调用函数
      invoke Inject
    .endif
	.elseif eax==WM_CLOSE
		invoke EndDialog,hWin,0
	.else
		mov		eax,FALSE
		ret
	.endif
	mov		eax,TRUE
	ret

DlgProc endp



end start

2 把注入代码用汇编写,然后生成动态库,把动态库的代码注入到目标进程

1 用radAsm生成汇编代码的dll
1.1创建一个dll工程
1.2在工程----工程选项-----链接中加上/entry:_DllMainCRTStartup@12
**注意:**加上dllmain入口点才能编译,而_DllMainCRTStartup@12在msvcrt.lib库中,但是radAsm的msvcrt.lib库是旧的,没有_DllMainCRTStartup@12,所以自己要去vc中找一个新的msvcrt.lib库去D:\RadASM\masm32\lib目录中进行替换,如果是静态库需要用libc.lib
**说明:**如果不是dll,必须指明入口点,如果不指明的话,程序不会在调用入口初始化程序,这样的话有些api是用不了的,因为这些api必须要初始化后功能才是正确的
代码如下
injectDll.Asm

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive


include windows.inc
includelib msvcrt.lib
include kernel32.inc
includelib kernel32.lib

.code


InjectCode proc
  push 00646c72h
  push 6f57206fh
  push 6c6c6568h
  mov  ebx, esp
  push 00000065h
  push 6c746954h
  mov ecx, esp
  push MB_OK
  push ecx
  push ebx
  push NULL
LABEL1:
  mov  eax, 12345678h
  call eax
  add  esp, 20
  retn  4
InjectCode endp



GetCodeSize proc
  
  mov eax, GetCodeSize -  InjectCode
  ret

GetCodeSize endp
end

injectDll.Def

 EXPORTS
  InjectCode
  GetCodeSize

编译连接生成dll,我另外生成了一个obj用来确定需要重定位地址偏移位置
2在vs中写注入流程代码,核心代码如下

extern "C" int _stdcall GetCodeSize();//这个是obj的函数,obj可以直接加载到vs工程中,函数声明一下就可以使用,这也是c调汇编比较简单的方式

void CMFCInjectionDlg::OnBnClickedInjection()
{
    //首先得到点击的位置
    POSITION pos = m_listCtrl.GetFirstSelectedItemPosition();
    if (pos == NULL)
    {
        MessageBox("请至少选择一项或者遍历进程", "选择", MB_ICONEXCLAMATION);
        return;
    }
    //得到行号,通过POSITION转化
    int nId = (int)m_listCtrl.GetNextSelectedItem(pos);
    //得到列中的内容(0表示第一列,同理1,2,3...表示第二,三,四...列)
    string str = m_listCtrl.GetItemText(nId, 0);

    DWORD dwProcessId = atoi(str.c_str());
	//1打开进程
    HANDLE hProces = OpenProcess(
        PROCESS_ALL_ACCESS,
        FALSE,
        dwProcessId);

    // 2 在目标进程申请内存,写入注入代码
    LPVOID pDllPathOfDstProc =
        VirtualAllocEx(
        hProces,
        NULL, //系统自动分配地址
        0x1000, //申请内存大小
        MEM_COMMIT, //物理映射
        PAGE_READWRITE //可读可写
        );
    if (pDllPathOfDstProc == NULL)
    {
        AfxMessageBox(_T("申请内存失败"));
        return;
    }

    //获取目标进程的函数地址
    HMODULE hUser = GetModuleHandle("user32.dll");
    LPVOID pMessageBoxA = GetProcAddress(hUser, "MessageBoxA");
    if (pMessageBoxA == NULL)
    {
        AfxMessageBox(_T("获取MessageBoxA地址失败"));
        return;
    }
    int pBase = (int)hUser;
    int pDest = (int)pMessageBoxA;
    int pOffset = pDest - pBase;
    int pModifValue = pBase + pOffset;//获取api实际地址


    //重定位地址
    int nOffset = GetCodeSize();//获取要重定位位置偏移
    nOffset -= 4;//在这个位置修改
    HMODULE hModule = LoadLibrary("injectDll.dll");
    LPVOID pLoadLibrary = GetProcAddress(hModule, "InjectCode");
    if (pLoadLibrary == NULL)
    {
       AfxMessageBox(_T("获取InjectCode地址失败"));
       return;
    }
    DWORD dwOld2;
    VirtualProtect(pLoadLibrary, 0x1000, PAGE_EXECUTE_READWRITE, &dwOld2);    //修改内存属性
    int nAdder = (int)pLoadLibrary + nOffset;
    int* pAdder = (int*)nAdder;
    *pAdder = pModifValue;//重定位api地址

    //获取要注入代码的大小
    typedef int(*PFN_GetCodeSize)(void);
    PFN_GetCodeSize pfnGetCodeSize = (PFN_GetCodeSize)GetProcAddress(hModule, "GetCodeSize");
    if (pLoadLibrary == NULL)
    {
        AfxMessageBox(_T("获取MessageBoxA地址失败"));
        return;
    }
    DWORD nSize = pfnGetCodeSize();


    //修改目标内存属性
    DWORD dwOld;
    VirtualProtectEx(hProces ,pDllPathOfDstProc, 0x1000, PAGE_EXECUTE_READWRITE, &dwOld);

    DWORD dwBytestToWrite = 0;
    BOOL bRet = WriteProcessMemory(
        hProces,
        pDllPathOfDstProc,//写入内存的首地址
        pLoadLibrary,
        nSize,
        &dwBytestToWrite);
    if (!bRet)
    {
        AfxMessageBox(_T("写入路径失败"));
        return;
    }
    // 3) 创建远程线程,目标进程创建了一个线程,执行目标线程的线程回调函数
    HANDLE m_hRemoteThread = CreateRemoteThread(
        hProces,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)pDllPathOfDstProc, //在目标进程中的回调函数的地址
        NULL,//此时内存存放的是dll,这时候调用pLoadLibrary线程回调函数就会把dll当做参数传进去,就把dll加载进去了,
        0,
        NULL);
    if (m_hRemoteThread == NULL)
    {
        AfxMessageBox(_T("远程线程创建失败"));
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值