• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-60  評論-262  文章-1  trackbacks-0
             
                 摘要:   閱讀全文
            posted @ 2008-09-05 16:32 free2000fly 閱讀(4619) | 評論 (32)編輯 收藏
                 摘要:   閱讀全文
            posted @ 2008-07-30 09:23 free2000fly 閱讀(1518) | 評論 (0)編輯 收藏
                 摘要:   閱讀全文
            posted @ 2008-07-24 17:24 free2000fly 閱讀(602) | 評論 (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 閱讀(3785) | 評論 (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 閱讀(1779) | 評論 (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 閱讀(2299) | 評論 (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 閱讀(2235) | 評論 (0)編輯 收藏
            http://blog.tinybrowser.net/archives/926

            posted @ 2008-06-21 22:24 free2000fly 閱讀(3705) | 評論 (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 閱讀(3263) | 評論 (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 閱讀(2401) | 評論 (0)編輯 收藏
            僅列出標題
            共6頁: 1 2 3 4 5 6 
            久久久91精品国产一区二区三区| 久久精品国产影库免费看| 久久综合九色欧美综合狠狠| 久久久久无码国产精品不卡| 一97日本道伊人久久综合影院| 人妻中文久久久久| 国产精品久久久久jk制服| 国产女人aaa级久久久级| 久久精品国产清自在天天线| 色综合久久中文色婷婷| 区久久AAA片69亚洲| 国内精品久久久久影院免费| 亚洲精品无码久久毛片| 精品国产91久久久久久久| 精品国产乱码久久久久软件| 天天久久狠狠色综合| 色综合久久久久无码专区| 国产福利电影一区二区三区久久老子无码午夜伦不| 久久精品一区二区影院| 99久久中文字幕| 久久久亚洲欧洲日产国码二区| 久久亚洲国产精品一区二区| 欧美va久久久噜噜噜久久| 亚洲&#228;v永久无码精品天堂久久 | 人妻无码久久一区二区三区免费 | 久久久久久久亚洲Av无码| 久久午夜综合久久| 中文字幕亚洲综合久久2| 久久男人Av资源网站无码软件| 久久精品国产99国产电影网| 亚洲愉拍99热成人精品热久久 | …久久精品99久久香蕉国产| 亚洲精品国产第一综合99久久| 99久久超碰中文字幕伊人| 精品久久久一二三区| 久久久这里有精品| 久久毛片一区二区| 人妻无码αv中文字幕久久琪琪布 人妻无码精品久久亚瑟影视 | 久久久精品久久久久久 | 性高朝久久久久久久久久| 久久精品亚洲欧美日韩久久|