学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题
发表于 2020-9-1 11:05:43 | 查看: 4332| 回复: 0
  这节课的目标是把上节课的ThreadProc函数通过纯汇编语言注入到notepad.exe进程
  等会要用到内联汇编,将汇编指令插入到C语言代码中,使用的工具可以是MASM,这里为了方便起见,我使用OllyDbg的汇编命令编写汇编代码
  首先随便拿一个程序当做我们写汇编代码的载体,这里使用asmtest.exe当载体,载入od后,goto到401000写代码

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  把401000设为eip(下一条执行的指令)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  取消“使用nop填充的功能”,如果选中的话,输入代码的长度短于已有代码时,剩余长度会填充为nop指令(No Operation),以整体对齐代码
  下面使用汇编语言写ThreadProc()函数,与上节课使用C语言编写的ThreadProc()函数相比,其不同之处在于,需要的字符串包含在Code中(参数都在代码段),这里要注意,代码段一般情况下只有可读权限,如果强制写数据,需要通过PE头修改代码段的权限。

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  以上就是完整的代码,现在保存到可执行文件(asmtest_patch.exe)
  下面将刚写的汇编代码通过C语言的混合注入到notepad.exe中

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  然后保存到文件

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  把每个16进制前面加上0x 后面加上 逗号
  用Word打开txt文件,然后用Ctrl+H打开替换对话框,勾选使用通配符,在查找中输入[0-9A-Z]{2},替换为中输入0x^&, 单击全部替换即可。

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  转换完成了

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  下面看一下注入程序的源码
#include "windows.h"

#include "stdio.h"



typedef struct _THREAD_PARAM

{

    FARPROC pFunc[2];               // LoadLibraryA(), GetProcAddress()

} THREAD_PARAM, *PTHREAD_PARAM;



BYTE g_InjectionCode[] =

{

  0x55, 0x8B, 0xEC, 0x8B, 0x75, 0x08, 0x68, 0x6C, 0x6C, 0x00, 0x00, 0x68, 0x33, 0x32,

  0x2E, 0x64, 0x68, 0x75, 0x73, 0x65, 0x72, 0x54, 0xFF, 0x16, 0x68, 0x6F, 0x78, 0x41,

  0x00, 0x68, 0x61, 0x67, 0x65, 0x42, 0x68, 0x4D, 0x65, 0x73, 0x73, 0x54, 0x50, 0xFF,

  0x56, 0x04, 0x6A, 0x00, 0xE8, 0x0C, 0x00, 0x00, 0x00, 0x58, 0x75, 0x65, 0x6E, 0x69,

  0x78, 0x69, 0x61, 0x6E, 0x67, 0x00, 0x00, 0xE8, 0x14, 0x00, 0x00, 0x00, 0x77, 0x77,

  0x77, 0x2E, 0x78, 0x75, 0x65, 0x6E, 0x69, 0x78, 0x69, 0x61, 0x6E, 0x67, 0x2E, 0x63,

  0x6F, 0x6D, 0x20, 0x00, 0x6A, 0x00, 0xFF, 0xD0, 0x33, 0xC0, 0x8B, 0xE5, 0x5D, 0xC3

};



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;

}



BOOL InjectCode(DWORD dwPID)

{

    HMODULE         hMod            = NULL;

    THREAD_PARAM    param           = {0,};

    HANDLE          hProcess        = NULL;

    HANDLE          hThread         = NULL;

    LPVOID          pRemoteBuf[2]   = {0,};



    hMod = GetModuleHandleA("kernel32.dll");



    // set THREAD_PARAM

    param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");

    param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");



    // 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

    if( !(pRemoteBuf[0] = VirtualAllocEx(hProcess,                  // hProcess

                                         NULL,                      // lpAddress

                                         sizeof(THREAD_PARAM),      // 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

                            sizeof(THREAD_PARAM),                   // nSize

                            NULL) )                                 // [out] lpNumberOfBytesWritten

    {

        printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());

        return FALSE;

    }



    // Allocation for ThreadProc()

    if( !(pRemoteBuf[1] = VirtualAllocEx(hProcess,                  // hProcess

                                         NULL,                      // lpAddress

                                         sizeof(g_InjectionCode),   // 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)&g_InjectionCode,               // lpBuffer

                            sizeof(g_InjectionCode),                // 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],

                                       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;

}



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;

}
  输入注入指令 成功的给notepad.exe添加了一个弹窗

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  下面对注入过程进行逆向分析:
  首先用OD载入notepad.exe 并且运行起来
  然后OD选项-调试设置-中断于新线程

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  现在注入代码,输入注入指令后,OD会中断

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  如果出现下面这种情况,不用担心,只是OD把数据当成指令翻译了~~~~

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  这时候只要删除分析就可以了

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  现在开始逐行分析最关键的线程注入的过程
  1.生成栈帧(保证参数读取正确,函数结束时也方便清理堆栈空间)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  2.THREAD_PARAM结构体指针

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  查看结体构指针在notepad.exe进程内存空间中分配的内存缓冲区地址

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  3.拼接出user32.dll字符串

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 压栈user32.dll字符串首地址(调用字符串)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  结构体定义如下

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 调用LoadLibraryA(“user32.dll”)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  取esi中4个字节的数据,然后压栈下一条指令的地址,jmp到[esi],最后再retn esp

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  查看notepad.exe的user32.dll加载地址,发现和LoadLibraryA获取到的完全一致

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  6.拼接MessageBoxA字符串

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 调用GetProcAddress(hMod,“MessageBoxA”)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  Push esp 将MessageBoxA字符串压栈
  Push eax 将刚才获取到的user32.dll的加载地址压栈
  [esi+4]就是GetProcAddress的地址
  • 压入MessageBoxA的第四个参数

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 压入MessageBoxA函数的第三个参数(xuenixiang)
  下面介绍 使用call指令将包含在代码间的字符串数据地址压入栈 的技术(非常巧妙)
  大家都知道call xx指令=push下一条指令地址+jmp xx

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  首先,执行A2002E处的指令使得MessageBoxA的第四个参数0入栈,然后call A2003F,这时候call的下一行指令的地址A20033就会被压入栈顶,但A20033地址下的内容并不是指令,而是我们预先存储的字符串首地址(字符串指针),这个字符串如图所示为Xuenixiang(此时第三个参数也进栈了),然后jmp到A2003F。
  9.压入MessageBoxA函数的第二个参数(www.xuenixiang.com

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  和上面类似,利用call指令把A20044-A20056处的字符串指针A20044(第二个参数)压栈,然后jmp到A20058
  • 压入MessageBoxA函数的第一个参数

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  将第一个参数压栈,最后执行call eax (eax是前面获取到的MessageBoxA函数地址)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 设置ThreadProc函数的返回值

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  • 删除栈帧及函数返回

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)

【windows代码注入教程】第六课 代码注入(汇编语言)
  写到这里我又一次感受到栈帧的强大之处(始终保持堆栈的变量读取平衡)
  DLL注入的全部教程到此结束,接下来会开始讲解API HOOK
            
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

GMT+8, 2024-4-25 08:47 , Processed in 0.120994 second(s), 42 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表