随笔-60  评论-262  文章-1  trackbacks-0
 
     摘要:   阅读全文
posted @ 2008-09-05 16:32 free2000fly 阅读(4581) | 评论 (32)编辑 收藏
     摘要:   阅读全文
posted @ 2008-07-30 09:23 free2000fly 阅读(1510) | 评论 (0)编辑 收藏
     摘要:   阅读全文
posted @ 2008-07-24 17:24 free2000fly 阅读(595) | 评论 (0)编辑 收藏
之所以有此一问, 是因为不同版本的 Windows, 甚至同一版本的不同 SP, 其内核数据结构是不同的, 而开发驱动程序经常要直接操纵这些内核数据结构, 就必须得到 Windows 版本的详细信息.

如何在内核里取得 windows 详细版本号始终是困扰驱动开发人的一个不大不小的问题, 因为 PsGetVersion 函数的最后一个参数根本就不起作用, 得不到 SP 版本号, 而 RtlGetVersion 函数是在 Windows XP 才提供的, 不具通用性.

因此, 我写了一个函数, 将这两个函数封装在一起, 让其首先试图调用 RtlGetVersion 函数, 如果失败了, 表明这肯定是 Windows 2000 及以下系统, 目前我们一般只支持到 Windows 2000, 至于 undocumented 内核数据结构, Windows 2000 下的都是一样的, 所以就不做 sp 版本判断了.

typedef enum WIN_VER_DETAIL {
    WINDOWS_VERSION_NONE,       //  0
    WINDOWS_VERSION_2K,
    WINDOWS_VERSION_XP,
    WINDOWS_VERSION_2K3,
    WINDOWS_VERSION_2K3_SP1_SP2,
    WINDOWS_VERSION_VISTA,
} WIN_VER_DETAIL;

typedef NTSTATUS (NTAPI * PFN_RtlGetVersion)(OUT PRTL_OSVERSIONINFOW lpVersionInformation);

EXTERN_C WIN_VER_DETAIL GetWindowsVersion()
{
    UNICODE_STRING ustrFuncName = { 0 };
    RTL_OSVERSIONINFOEXW osverinfo = { sizeof(osverinfo) };
    PFN_RtlGetVersion pfnRtlGetVersion = NULL;

    RtlInitUnicodeString(&ustrFuncName, L"RtlGetVersion");
    pfnRtlGetVersion = MmGetSystemRoutineAddress(&ustrFuncName);

    if (pfnRtlGetVersion)
    {
        kdprintf("[xxxxxxxx] Using \"RtlGetVersion\"\n");
        pfnRtlGetVersion((PRTL_OSVERSIONINFOW)&osverinfo);
    }
    else
    {
        kdprintf("[xxxxxxxx] Using \"PsGetVersion\"\n");
        PsGetVersion(&osverinfo.dwMajorVersion, &osverinfo.dwMinorVersion, &osverinfo.dwBuildNumber, NULL);
    }

    kdprintf("[xxxxxxxx] OSVersion NT %d.%d:%d sp%d.%d\n",
        osverinfo.dwMajorVersion, osverinfo.dwMinorVersion, osverinfo.dwBuildNumber,
        osverinfo.wServicePackMajor, osverinfo.wServicePackMinor);

    if (osverinfo.dwMajorVersion == 5 && osverinfo.dwMinorVersion == 0) {
        return WINDOWS_VERSION_2K;
    } else if (osverinfo.dwMajorVersion == 5 && osverinfo.dwMinorVersion == 1) {
        return WINDOWS_VERSION_XP;
    } else if (osverinfo.dwMajorVersion == 5 && osverinfo.dwMinorVersion == 2) {
        if (osverinfo.wServicePackMajor==0) {
            return WINDOWS_VERSION_2K3;
        } else {
            return WINDOWS_VERSION_2K3_SP1_SP2;
        }
    } else if (osverinfo.dwMajorVersion == 6 && osverinfo.dwMinorVersion == 0) {
        return WINDOWS_VERSION_VISTA;
    }

    return WINDOWS_VERSION_NONE;
}


posted @ 2008-07-23 01:40 free2000fly 阅读(3755) | 评论 (0)编辑 收藏

作者: churui 2005-11-05 12:22

某日,遇到一个奇怪的程序(你也许并不关心它的名字,我们就姑且称它为程序A)。这个程序是十分霸道的,在与我的程序(你也肯定不会关心它的名字,所以我们称为程序B)同时执行的时候,总能从程序B(这里也就是进程B了)的数据段中读取到一些内容。这一点让我非常不爽,于是我决定给B加入自我保护的功能,让A不能轻易的读取。听起来有点象“磁心大战”?呵呵,总之交锋就是这样开始的,初衷也非常简单,而争夺的过程倒是几经波折。

       在战斗开始之前,还需要说明的是,这里的AB都是GUI程序,而且B总是先于A执行。

       考虑一下A读取B的数据段,我能想到的也就是三种方法:
1.
读取映象文件  
2.
使用ReadProcessMemory   
3.
注入进程B,然后直接读取。

对于第一种方法,只要B加一个简单的壳,A就无计可施。所以比较实用的还是后两种方法。经过观察,发现A在执行过程中给进程B注入了一个DLL所以我判断A可能使用的是第三种方法。

       AB注入DLL,一般来说也就是三种方法。但是不管哪种方法,我认为最终总要调用ntdll!LdrLoadDll。于是,最原始的办法就是在进程Bhook LdrLoadDll这个API,拦截可疑的DLL。实现的过程并不复杂,可惜没有效果。也就是说,A在注入DLL的过程中,根本没有被B拦截到。

       我使用IceSword,监视A的启动过程。发现A在启动时会在每个进程(当然,除了一些特殊的系统进程如Idlecsrss等等)中创建一个远线程。因此,我希望能把创建远线程拦截下来。考虑到一般创建远线程之前总要先用kernel32!OpenProcess得到进程句柄,我就试图在ring3使用hook api拦截所有的OpenProcess。可惜我的努力又失败了。本来hook OpenProcess工作的挺好,但是只要A一启动,对OpenProcesshook马上失效。考虑到前面hook ntdll!LdrLoadDll也没有奏效,我认为A一定采取了某些防止hook api的手段。

       在这种情况下,我打算到ring0去解决问题。由于之前我只有win32的开发经验,而driver几乎没有做过,拿着罗云彬老大翻译的Kmd教程中文版恶补两天,又在driverdevelop找了一些源码和资料,终于拼凑出了一个勉强能运行的driver。功能倒也简单,就是通过修改SSDTSystem Service Dispatch Table)。使得ntdll!NtOpenProcess执行到核心态的时候,能够被我拦截下来。

       这次还是失败了,而且失败的情况也和ring3如出一辙:本来ntdll!NtOpenProcess能够被拦截下来的,一旦A启动后,所有的拦截立刻失效。让我啼笑皆非的是,我做了另外一个简单的程序C,唯一的作用就是使用kernel32!OpenProcess去打开B,结果当A启动后,连这个C也能成功的打开B了。使用IceSword一看,原来A启动后,SSDT会被自动改回最初的内容,真让我无语。

       driverdevelop上向等bmyyyudzhaock等几位大虾请教了好几次,得出了以下的结论:ntdll中导出了NtOpenProcessZwOpenProcess,而两者实际上是一回事。ntosknrl中也导出了NtOpenProcessZwOpenProces,而两者完全不同:ntosknrl!NtOpenProcess实际上就是“正常的”SSDT入口,而ntosknrl!ZwOpenProcess,不知道它是干什么的。如果修改SSDT,其实很容易被别人发现并且破掉(把入口换回NtOpenProcess就可以了)。那么有没有其他方法?看有的资料上说可以换int 2 e的中断处理函数,xp中既然用sysenter/syscall,看来这一招也不灵。最终,bmyyyud大虾提示我,可以改正常ntosknrl!NtOpenProcess的入口代码。(非入口~~~~)

       修改ntosknrl!NtOpenProcess的入口代码比修改SSDT难度要大一些。首先ntosknrl!NtOpenProcess的代码所在页面具有只读属性,在修改页面前需要先修改CR0寄存器的第16bit,否则一定是蓝屏没商量,对于我这样的新手来说,这还真有点让人无所适从。其次,为了修改入口代码,最方便的方法是使用微软的detours,可惜detours中引用了很多ring3API,无法直接使用。只好拿来detours的源码,把不必要的细枝末节都剪裁掉,把所有使用到ring3 API的部分都尽量去掉或者ring0API代替。只留下最关键的部分,试着run了一把,没想到居然能运行。

       这样做完之后,发现A程序调用ntosknrl!NtOpenProcess并且被我拦截了,颇感欣慰……没想到见鬼的是,在A程序调用ntosknrl!NtOpenProcess失败的情况下,它仍然给B创建了一个远线程。这个时候zhaock大虾告诉我,即使不调用NtOpenProcess也可以调用PsLookupProcessByProcessIdObOpenObjectByPointer来达到同样的目的。看来还需要拦截ntosknrl!NtCreateThread,保险起见,把ntosknrl!NtReadVirtualMemory也拦截下来。一切做完后,试运行,终于把A彻底拦住了,它再也没能用B中读出一个字节….. 忽然想到huyg师兄曾经说的“资料不是最重要的,蛮干才是最重要的”……(不敢苟同~~~~)
posted @ 2008-07-21 15:37 free2000fly 阅读(1744) | 评论 (1)编辑 收藏
用 VC6 和 VC71 装载的 ATL 开发软件的人都知道, 当我们定义了一个自销毁窗口时, 一般在 ATL 窗口类的

virtual void OnFinalMessage(HWND ){...}

函数内加一句

delete this;

然后就返回了. 但是气人的是, 每次当我们返回后, 总有一个地方断言失败,

ATLASSERT(pThis->m_pCurrentMsg == &msg);

Google 了许久, 没有满意的解决方案, 包括微软的方案

http://support.microsoft.com/kb/202110

也不好, 自己想尽办法还是 "山重水复疑无路", 后来突然灵光突现, 彻底解决, 就一个函数调用而已: IsWindow(...). 现在, 终极解决方案是这样的:
搜索 atlwin.h 文件内的 "ATLASSERT(pThis->m_pCurrentMsg == &msg);" 字符串 (在文件内有 3 处), 将其原始内容
    LRESULT lRes;
    BOOL bRet 
= pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
    
// restore saved value for the current message
    ATLASSERT(pThis->m_pCurrentMsg == &msg);
    pThis
->m_pCurrentMsg = pOldMsg;
改成
    LRESULT lRes;
    BOOL bRet 
= pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
    
if(FALSE == ::IsWindow(pThis->m_hWnd)) {
        return
 lRes; // 在 CDialogImplBaseT 类里是 return FALSE;  特此说明
    }
    
// restore saved value for the current message
    ATLASSERT(pThis->m_pCurrentMsg == &msg);
    pThis
->m_pCurrentMsg = pOldMsg;
其中红色的代码为我们的修正代码. 万事大吉. 再也不会出现断言失败了.

道理是这样的: 如果 pThis 对象被删除了的话, 那么 pThis 本身和其成员变量 m_hWnd 都将是一个无效值, 那么后续的操作将毫无意义. 因此直接返回, 不用废话.

真是简单的思路直指问题的核心啊.

posted @ 2008-07-02 15:44 free2000fly 阅读(2250) | 评论 (4)编辑 收藏

原始链接: https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3223434&SiteID=1

Hi Guys,

My goal is to run a program before user even log on to system in vista. Here are couple of links i have already went through. These codes are working fine when ever we are dealing with WinSta0\\default desktop when user is log on but my requirements are different.

http://www.codeproject.com/KB/vista-security/VistaSessions.aspx?fid=406624&sort=Position&noise=3&view=Quick&mpp=50&df=1

http://www.uvnc.com/vista/

http://www.codeproject.com/KB/vista-security/VistaSessionsC_.aspx

Steps that wosks fine
-------------------------------

  1. Get the Active Console SessionId using WTSGetActiveConsoleSessionId
  2. Since I need to launch the application under a system account, I use the token from Winlogon, since Winlogon runs under the system account. So I obtain the process ID of Winlogon and Duplicate the token.
  3. Then I make sure I sent the startupinfo parameter lpDesktop to winsta0\Default since I need to launch my process there.
  4. Then I use CreateProcessAsUser with Winlogon's duplicate token to launch my process into session 1.
  5. That's all. I am done.
I got this working on Vista but I would like to launch a progrma to the WinSta0\\Winlogon desktop. Anyone have any ideas? When I change the desktop to WinSta0\\Winlogon the application does not appear on the logon screen. However, when I run the program on XP it works.

Vista must have the Winlogon Desktop permissions set differently, I added "SeTcbPrivilege" but that did no good. Also, if I look at taskmgr I see the program started along with CreateProcessAsUser not returning any errors. It appears to work, just cannot see the application on the WinSta0\\Winlogon desktop. Anyone have any ideas?

 

==================================================================================================

It works! with vista !!

1. WTSGetActiveConsoleSessionId();
2. WTSQueryUserToken() for winlogon.exe winlogon pid
3. DuplicateTokenEx ()
4. AdjustTokenPrivileges ()
5. CreateProcessAsUser () lpDesktop to Winsta0\Winlogon

Fire the executable via taskscheduler (schtasks.exe) with SYSTEM priveleges.


Muhahahaha , and then if you dont see youre app in the winlogon desktop, try hitting ALT+TAB .... in the winlogon desktop.

I hope microsoft keeps this entry point for showing things on the secure desktop, cause we use it to show the unattended installation progress, I think the secure desktop should stay accessible in future releases.

(btw, I did not test it with FUS Fast User Switching, It worked with a domain account setting, this means Fast User Switching is not enabled).


Much appreciated,

 mon11.

 

==================================================================================================

Fast User Switching is enabled for domain accounts in Vista by default, so that's not necessarily true.

==================================================================================================

AndyCadley,
You are right, I tested it, it works also with FUS.

 

 其他连接:

[1]  http://blogs.msdn.com/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx

[2]  http://blogs.technet.com/askperf/archive/2007/07/24/sessions-desktops-and-windows-stations.aspx

posted @ 2008-06-28 08:22 free2000fly 阅读(2206) | 评论 (0)编辑 收藏
http://blog.tinybrowser.net/archives/926

posted @ 2008-06-21 22:24 free2000fly 阅读(3696) | 评论 (11)编辑 收藏
今天终于完成了往 vista 内所有 ring 3 进程的注入. 包括 csrss.exe 进程.

主要的中心思想就是,
    1. 提升本进程访问令牌, 使其有调试权限.
    2. 获得本进程的当前线程的内核对象的安全描述符, 将其复制出来备用.
    3. 准备远程线程的执行代码以及执行参数. 其中包括 loadlibrarya 和 RtlExitUserThread 调用, 例子嘛, 本来前一篇文章里有, 再次贴在这里方便各位看官.
#define LoadLibraryA_ADDR       0xDDDDDDDD 
#define RtlExitUserThread_ADDR  0xEEEEEEEE 

static __declspec(naked) DWORD WINAPI ThreadDummy(LPVOID lpParam) 
{
    __asm { 
        push    dword ptr [esp
+4]           ; // 将传进来的线程函数的参数压栈 
        mov     eax, LoadLibraryA_ADDR      ; // LoadLibraryA 或 FreeLibrary 函数的地址 
        call    eax                         ; // 调用 LoadLibraryA 函数
        push    eax                         ; // 将 RtlExitUserThread 函数的参数压栈
        mov     eax, RtlExitUserThread_ADDR ; // RtlExitUserThread 函数的地址 
        call    eax                         ; // 调用 RtlExitUserThread 函数
        ret     4                           ; // 返回 
    } 
}

    4. 以第 2 步获取的安全描述符以及第 3 步准备的代码和数据作为参数调用 RtlCreateUserThread 函数, 在目标进程创建远线程. 等待执行完毕.
    5. 清理第 2 步和第 3 步分配的内存. 整个过程完毕.

总结: 整个 dll injection 的探索开发历时月余, 开始看似顺利, 后期艰难困苦. 特别是那个超级变态要求: 必须注入到 csrss.exe 进程里去. 从普通的 SetWindowHookEx 和 known dll, 到 CreateRemoteThread, 最后到 NtCreateThread 以及 NtCreateThreadEx, 最后回归到 RtlCreateUserThread 函数. 中间夹杂了 DPC, APC, 以及在内核修改 knowndlls\\kernel32.dll 可执行映像 inline hook CreateThread 函数等等等等. 从应用层到内核, 再回归应用层, 搞了个遍.

现在我可以牛逼哄哄的说一句了, Injection DLL? Just so so!!!

顺便 BS 一下 Rising, 这个宝贝杀软竟然直接 kill 掉了所有远程线程函数, 不对用户做任何通知和给用户选择的机会. 但我在内核修改任何可执行映像时, 这个宝贝却愉快的告诉我, 我的系统很安全. 再次 BS 一下.

一个小小的测试程序, 在这里下载

posted @ 2008-06-20 11:24 free2000fly 阅读(3237) | 评论 (11)编辑 收藏

说明: 前段时间找关于向系统进程注入链接库的文章, 找到这篇, 加入收藏夹, 但后来这个连接死活打不开了. 就用 google 的 cache 功能将文章 A 在这里. 查阅方便.

For a while now, I've been searching for the optimal way to inject code into privileged Win32 processes like lsass.exe, csrss.exe, and winlogon.exe.

There are many functions such as the LSA and SAM exports that even users logged in with full administrative rights cannot execute
unless they do so under the context of one of these privileged processes.

There are a few tricks that I learned along the way.

First, it is necessary to adjust the token privileges of your program so that debugging (SE_PRIVILEGE_ENABLED) is allowed.

If you are injecting code into a lower privileged process, then this will not be needed.

Also, the target process will need to be opened with PROCESS_ALL_ACCESS rights.

Its all pretty easy on Windows 2000 and XP Service Pack 0 and 1.
On these systems, you can use the documented CreateRemoteThread() function, but first the code you want
to run in the security context of the remote process needs to exist in that process' virtual memory space.
You can put it there by using VirtualAllocEx() and WriteProcessMemory().

With XP SP2 and later (2003, Vista) some new security measures prevent the traditional CreateRemoteThread() function from working properly.
You should be able to open the process, allocate memory on its heap, and write data to the allocated region,
but when trying to invoke the remote thread, it will fail with ERROR_NOT_ENOUGH_MEMORY.

On Vista, I found that an author can substitute the CreateRemoteThread() call with NtCreateThreadEx() export from ntdll.dll
and it will allow for the thread to execute properly. This requires you to auto-detect the version of the operating system and
branch to this different call if on Vista.

Also, this is isn't really a universal solution, because NtCreateThreadEx() doesn't exist on pre-Vista sytsems.
So now we're stuck with using CreateRemoteThread() on 2000 and XP SP 0,1 and NtCreateThreadEx() on Vista.
This is already getting messy, and we still don't have a solution for XP SP2.

Also, the NtCreateThreadEx() function takes an undocumented structure, whose members can be initialized appropriately
by reversing other binaries that use the function, but it looks really ugly in source code since I don't really know what the members are for,
or why particular values are significant.

For XP SP2 I did a little debugging and found that inside CreateRemoteThread(), there is a call to ZwCreateThread() which is an export
from ntdll.dll. The call is made while specifying that the thread should start suspended, which it does properly,
however down the road still inside CreateRemoteThread() before ZwResumeThread() is called, there is a call to CsrClientCallServer()
which fails and eventually leads to the error message.

This behavior makes you wonder, if you can just call ZwCreateThread() directly, then the call to CsrClientCallServer() will be avoided
and the thread will execute. The problem is that ZwCreateThread() doesn't allow one to set the thread start address easily
(you have to configure the INITIAL_TEB members to set EIP to your start address using mostly undocumented structures and functions).

However, this all can be avoided by using the RtlCreateUserThread() function instead,
which configures and calls all the undocumented functions for you, and eventually invokes ZwCreateThread() with the result.
Although RtlCreateUserThread() is undocumented also, its hardly as complex as the rest and is pretty simple to use.

At this point, we can successfully execute remote threads into privileged processes across all target platforms,
but as mentioned before, its pretty messy.

We're using three different, largely undocumented functions and auto-detecting which one to use based on the OS version.

The better solution is to create a secondary program that adds a service object (your injector program)
to the service control manager database on the target system. Since you're administrator, which is required anyway,
you'll be able to add these entries and start the service. This will enable the injector program
to run with different access rights than normal code, and the traditional CreateRemoteThread()
will work properly on Windows 2000, all of XP, and 2003/Vista.

The API functions for adding and controlling the service are documented by MSDN and remain consistent across all of the platforms.

So, what is learned is that we can use a number of different functions to inject code into privileged remote processes,
including RtlCreateUserThread() on XP SP2, and NtCreateThreadEx() on Vista, but the optimal way is to install a temporary service
and allow CreateRemoteThread() to be the single API that accomplishes the task for all platforms.


PS:

Basically the needed access rights are identical to XP: In both OSs you need admin rights for system wide injection. However, in Vista when UAC is enabled even admin users don't have admin rights by default. So you need to right click your exe and choose "run as administrator" (as LeVuHoang has already said). Alternatively you can add a manifest to your exe which will tell Vista that your app needs admin rights. If you do that, you don't need to do the "run as admin" step, anymore. However, the end user will still have to confirm the operation. If you don't like all this you need to inject from a service (see HookProcessTermination demo).

One other thing to look for is that the hook dll needs enough NTFS rights or else it might not be injected into all processes successfully. Vista is a bit more strict there than XP was.

void Inject(HWND hWnd, char* strDll)
{
    GetWindowThreadProcessId(hWnd, 
&pId);
    HANDLE hProcess 
= OpenProcess(PROCESS_ALL_ACCESS, FALSE, pId);
    LPVOID lpRemoteAddress 
= VirtualAllocEx(hProcess, NULL, strlen(strDll), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, lpRemoteAddress, (LPVOID)strDll, strlen(strDll), NULL);
    CreateRemoteThread(hProcess, NULL, 
0,
        (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(
"Kernel32"), "LoadLibraryA"),
        lpRemoteAddress, 
0, NULL);


The API does not create threads in other sessions (this behavior is documented in MSDN).

One way to load a library into a process of another session is: Create a suspended thread (ntdll!RtlCreateUserThread) at kernel32!ExitThread, schedule an asynchronous procedure call (ntdll!NtQueueApcThread) at kernel32!LoadLibraryEx, resume the thread (kernel32!ResumeThread - this executes the pending APC), and wait for the end of the thread (kernel32!WaitForSingleObject). APCs do not return a value - therefore the return value of kernel32!LoadLibraryEx is lost. There is much more work required to use this method in the exact same manner as CreateRemoteThread(LoadLibrary) (includes reading the PEB’s loader structures).

Other hints:

    * Never ever use CreateRemoteThread on a target process that differs in 'bitness' (kernel32!IsWow64Process). On some Windows versions this freezes your calling thread.
    * Dynamically determine the kernel32’s image base (might not be loaded at all).

 


对于 RtlCreateUserThread 函数的线程函数, 以下是个示例:

#define LoadLibraryA_ADDR       0xDDDDDDDD 
#define RtlExitUserThread_ADDR  0xEEEEEEEE 

static __declspec(naked) DWORD WINAPI ThreadDummy(LPVOID lpParam) 
{
    __asm { 
        push    dword ptr [esp+4]           ; // 将传进来的线程函数的参数压栈 
        mov     eax, LoadLibraryA_ADDR      ; // LoadLibraryA 或 FreeLibrary 函数的地址 
        call    eax                         ; // 调用 LoadLibraryA 函数
        push    eax                         ; // 将 RtlExitUserThread 函数的参数压栈
        mov     eax, RtlExitUserThread_ADDR ; // RtlExitUserThread 函数的地址 
        call    eax                         ; // 调用 RtlExitUserThread 函数
        ret     4                           ; // 返回 
    } 
}

static __declspec(naked) DWORD WINAPI ThreadDummy_end(LPVOID lpParam) 

    __asm { 
        ret     4                            ; 
    } 
}

PUCHAR FindDWordFromBuffer(PUCHAR lpBuffer, UINT cchMax, DWORD dwValue) 

    PUCHAR pResult 
= NULL; 
    UINT nIter 
= 0
    
for (nIter=0; nIter<cchMax; nIter++
    { 
        
if ( *(DWORD *)(lpBuffer + nIter) == dwValue ) { 
            pResult 
= lpBuffer + nIter; 
            
break
        } 
    } 
    
return pResult; 


BOOL BuildRemoteThreadCode(OUT PUCHAR lpCode, UINT cchMax, BOOL bInject) 

    UINT nCodeLen 
= 0
    PUCHAR pIter 
= NULL; 
    DWORD dwFnAddr 
= 0
    
    
if (NULL==lpCode || 0==cchMax) { 
        
return FALSE; 
    } 
    
    nCodeLen 
= (PUCHAR) &ThreadDummy_end - (PUCHAR) &ThreadDummy; 
    
if (nCodeLen > cchMax) { 
        
return FALSE; 
    } 
    
    memcpy((
void *)lpCode, (void *&ThreadDummy, nCodeLen); 
    
    {
        pIter 
= FindDWordFromBuffer(lpCode, nCodeLen, LoadLibraryA_ADDR); 
        
if (NULL == pIter) { 
            
return FALSE; 
        } 
        
        
if (bInject) { 
            dwFnAddr 
= (DWORD) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryA"); 
        } 
else { 
            dwFnAddr 
= (DWORD) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "FreeLibrary"); 
        } 
        
        
if (0 == dwFnAddr) { 
            
return FALSE; 
        } 
        
*(DWORD *)pIter = dwFnAddr; 
    } 
    
    {
        pIter 
= FindDWordFromBuffer(lpCode, nCodeLen, RtlExitUserThread_ADDR); 
        
if (NULL == pIter) { 
            
return FALSE; 
        } 
        
        dwFnAddr 
= (DWORD) GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlExitUserThread"); 
        
if (0 == dwFnAddr) { 
            
return FALSE; 
        } 
        
*(DWORD *)pIter = dwFnAddr; 
    } 
    
    
return TRUE; 
}

自己分配一块足够大的内存, 以这块内存的指针作为参数调用 BuildRemoteThreadCode 函数后, 这块内存就可以写到目标进程里面, 并作为 RtlCreateUserThread 函数的线程函数执行了.

当然, 线程函数的参数, 还是得自己准备了, 也就是一个字符串指针或一个模块的 HMODULE. 相信大家都会, 不用我废话了.

posted @ 2008-06-18 17:31 free2000fly 阅读(2392) | 评论 (0)编辑 收藏
仅列出标题
共6页: 1 2 3 4 5 6