S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

about Injection

Posted on 2010-02-06 04:38 S.l.e!ep.¢% 阅读(1665) 评论(2)  编辑 收藏 引用 所属分类: RootKit
Injection 的主要流程
1. 进程启动
2. 如果在 vista 以上的系统,确保 ShutdownBlockReasonCreate && ShutdownBlockReasonDestroy (详见 ShutdownBlockReasonCreate Function )
3.
调用  SetProcessShutdownParameters (详见 SetProcessShutdownParameters Function )确保系统关机先询问本程序 (这里似乎有漏洞,如果其它程序调用了 SetProcessShutdownParameters 就可以抢在 ShutdownGuard 前面接收到 WM_QUERYENDSESSION 消息)
4.  PatchApps(0);
5.  开启定时器,定时检查并inject DLL SetTimer(hwnd, PATCHTIMER, PATCHINTERVAL, NULL);

PatchApps() 函数主要流程 (传0表示 inject dll, 传1表示 unload dll)
1. 确保 LoadLibraryA 和 FreeLibrary 这两个函数存在
2. 获取 SeDebugPrivilege (详见SeDebugPrivilege 特权 ) 确保能够访问到所有进程(调用了函数 OpenProcessToken    
    AdjustTokenPrivileges
)  (这里为了提升权限,如果这里没有提升权限,那么下面调用 VirtualAllocEx 分配内存 或
   WriteProcessMemory 写入内存将返回失败)
3. 调用 EnumProcesses  枚举所有进程
4. 采用 OpenProcess 函数打开进程,权限为 PROCESS_QUERY_INFORMATION
PROCESS_VM_READ
5. 获取 打开进程的全路径 GetModuleFileNameEx
    注入csrss.exe会蓝屏 / smss.exe 是注入不了的 / ShutdownGuard.exe 这个是我们的程序不需要注入
6. 检查下目标进程是否已经被注入过,如果是的话,忽略它 (它这里的判断好像有BUG,是根据 GetModuleFileNameEx 全路径的结果进行判断的, 如果写一个关机程序,启动两次,第二次启动的那个进程可以成功关闭?)
7. 判断下系统是不是  64 位的系统,如果是, 加载DLL也需要加载 64位的 (使用 IsWow64Process 来判断)
8. 使用 EnumProcessModules 函数来获取目标进程已经加载的模块
9. 判断下我们的 injection dll 是不是已经被目标进程加载,如果是,就忽略它(这个判断是否是多余的?
10. 判断下传进来的参数, 决定是否 inject dll 还是 unload dll
11. 屏蔽 SeDebugPrivilege 权限(使用 AdjustTokenPrivileges 函数)

InjectDLL() 的主要流程
1. 打开进程 OpenProcess(),权限为  PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ
PROCESS_CREATE_THREAD 为了 CreateRemoteThread
PROCESS_VM_OPERATION   为了 VirtualAllocEx
PROCESS_VM_WRITE|PROCESS_VM_READ 为了可以读写对方的内存
2. VirtualAllocEx 分配内存
3. WriteProcessMemory 写入内存
4. CreateRemoteThread 创建远程线程 (线程函数是 pfnLoadLibrary, injection dll)

加载injection dll 的主要流程
1. 修改目标进程 IAT 表中的 user32.dll  中的 ExitWindowsEx 函数, 将其代替为 ShutdownBlocked()

ShutdownBlocked() 的主要流程
1. 找到 ShutdownGuard 的窗口
2. 并发送 WM_SHUTDOWNBLOCKED 消息(通过 PostMessage() )

当收到  WM_QUERYENDSESSION 消息时
1. 如果是 vista 以上系统,需要调用 ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy

作了下实验,直接写个程序调用 ExitWindowsEx ,居然可以成功 Shut down,寒!!!
似乎只能阻止到 Explorer.exe

基本流程已经出来,收工

给我一个DLL,给我一个进程ID,我插,我插,我插插插。。。
bool InjectDLLToOtherProcess(DWORD dwProcessID, const char* pszDLLPath)
{
    HANDLE TokenHandle 
= NULL;

    
// 
    if ( FALSE == ::OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &TokenHandle) )
    {
        
return false;
    }
    
    TOKEN_PRIVILEGES tkp;
    
    
// Get LUID for SeDebugPrivilege
    if( FALSE == ::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid) )
    {
        ::CloseHandle(TokenHandle);
        
return false;
    }

    tkp.PrivilegeCount 
= 1;
    tkp.Privileges[
0].Attributes = SE_PRIVILEGE_ENABLED;
    
    
if ( FALSE == AdjustTokenPrivileges(TokenHandle, FALSE, &tkp, 0, NULL, NULL) ) 
    {
        ::CloseHandle(TokenHandle);
        
return false;
    }

    HANDLE process 
= ::OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ, TRUE, dwProcessID);
    
if ( process == NULL )
    {
        ::CloseHandle(TokenHandle);
        
return false;
    }

    typedef HMODULE (WINAPI 
*LoadLibraryPointor)(LPCTSTR);
    LoadLibraryPointor pfnLoadLibrary 
= NULL;
    HMODULE kernel32 
= NULL;
    
    
//Get address to LoadLibrary and FreeLibrary
    if (pfnLoadLibrary == NULL) 
    {
        kernel32 
= ::GetModuleHandle("kernel32.dll");
        
        
if ( kernel32 == NULL )
        {
            ::CloseHandle(process);
            ::CloseHandle(TokenHandle);
            
return false;            
        }
        
        pfnLoadLibrary 
= (LoadLibraryPointor)GetProcAddress(kernel32, "LoadLibraryA");
        
        
if (pfnLoadLibrary == NULL)
        {
            ::FreeLibrary(kernel32);
            ::CloseHandle(process);
            ::CloseHandle(TokenHandle);
            
return false;
        }
    }

    PVOID memory 
= ::VirtualAllocEx(process, NULL, strlen(pszDLLPath)+1, MEM_COMMIT, PAGE_READWRITE);
    
    
if ( memory == NULL )
    {
        ::FreeLibrary(kernel32);
        ::CloseHandle(process);
        ::CloseHandle(TokenHandle);
        
return false;
    }

    
if ( FALSE == ::WriteProcessMemory(process, memory, (void*)pszDLLPath, strlen(pszDLLPath)+1, NULL) )
    {
        ::VirtualFreeEx(process, memory, strlen(pszDLLPath)
+1, MEM_RELEASE);
        ::FreeLibrary(kernel32);
        ::CloseHandle(process);
        ::CloseHandle(TokenHandle);
        
return false;
    }

    
// Inject dll
    DWORD dwThreadID = 0;
    HANDLE hRemoteHandle 
= ::CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pfnLoadLibrary, memory, 0&dwThreadID);

    
if ( hRemoteHandle == NULL ) 
    {
        ::VirtualFreeEx(process, memory, strlen(pszDLLPath)
+1, MEM_RELEASE);
        ::FreeLibrary(kernel32);
        ::CloseHandle(process);
        ::CloseHandle(TokenHandle);
        
return false;
    }

    ::WaitForSingleObject(hRemoteHandle, INFINITE);

    DWORD dwReturn 
= 0;
    
if( FALSE == ::GetExitCodeThread(hRemoteHandle, &dwReturn) )
    {
        ::CloseHandle(hRemoteHandle);
        ::VirtualFreeEx(process, memory, strlen(pszDLLPath)
+1, MEM_RELEASE);
        ::FreeLibrary(kernel32);
        ::CloseHandle(process);
        ::CloseHandle(TokenHandle);
        
return false;
    }

    ::CloseHandle(hRemoteHandle);
    ::VirtualFreeEx(process, memory, strlen(pszDLLPath)
+1, MEM_RELEASE);
    ::FreeLibrary(kernel32);
    ::CloseHandle(process);
    ::CloseHandle(TokenHandle);
    
return true;
}

目前存在的已知问题:
1. 未考虑 64 位机器
2. 未考虑 DLL 加载失败的处理 (2010.02.05-23:38 已经 Fixed)
3. 提权后没有恢复

一天就这么过去了~

Feedback

# re: about Injection  回复  更多评论   

2010-02-06 00:39 by DrKN
This is a black paper. Not suitable to put here and it is illegal.

# re: about Injection  回复  更多评论   

2010-02-08 22:45 by Phirothing
@DrKN
It doesn't matter . And I like it.

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理