• <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  評(píng)論-262  文章-1  trackbacks-0

            說(shuō)明: 前段時(shí)間找關(guān)于向系統(tǒng)進(jìn)程注入鏈接庫(kù)的文章, 找到這篇, 加入收藏夾, 但后來(lái)這個(gè)連接死活打不開(kāi)了. 就用 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).

             


            對(duì)于 RtlCreateUserThread 函數(shù)的線程函數(shù), 以下是個(gè)示例:

            #define LoadLibraryA_ADDR       0xDDDDDDDD 
            #define RtlExitUserThread_ADDR  0xEEEEEEEE 

            static __declspec(naked) DWORD WINAPI ThreadDummy(LPVOID lpParam) 
            {
                __asm { 
                    push    dword ptr [esp+4]           ; // 將傳進(jìn)來(lái)的線程函數(shù)的參數(shù)壓棧 
                    mov     eax, LoadLibraryA_ADDR      ; // LoadLibraryA 或 FreeLibrary 函數(shù)的地址 
                    call    eax                         ; // 調(diào)用 LoadLibraryA 函數(shù)
                    push    eax                         ; // 將 RtlExitUserThread 函數(shù)的參數(shù)壓棧
                    mov     eax, RtlExitUserThread_ADDR ; // RtlExitUserThread 函數(shù)的地址 
                    call    eax                         ; // 調(diào)用 RtlExitUserThread 函數(shù)
                    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; 
            }

            自己分配一塊足夠大的內(nèi)存, 以這塊內(nèi)存的指針作為參數(shù)調(diào)用 BuildRemoteThreadCode 函數(shù)后, 這塊內(nèi)存就可以寫(xiě)到目標(biāo)進(jìn)程里面, 并作為 RtlCreateUserThread 函數(shù)的線程函數(shù)執(zhí)行了.

            當(dāng)然, 線程函數(shù)的參數(shù), 還是得自己準(zhǔn)備了, 也就是一個(gè)字符串指針或一個(gè)模塊的 HMODULE. 相信大家都會(huì), 不用我廢話了.

            posted on 2008-06-18 17:31 free2000fly 閱讀(2406) 評(píng)論(0)  編輯 收藏 引用

            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            香蕉久久AⅤ一区二区三区| 久久婷婷五月综合色高清| 国产成人精品久久亚洲高清不卡 | 久久久青草久久久青草| 欧美激情精品久久久久久久| 国产69精品久久久久观看软件| 久久精品99久久香蕉国产色戒 | 久久综合九色综合久99| 久久精品国产黑森林| av无码久久久久久不卡网站| 日韩久久无码免费毛片软件| 国产精品一久久香蕉国产线看| 国内精品伊人久久久久影院对白| 亚洲国产精品久久电影欧美| 色综合久久夜色精品国产| 久久99中文字幕久久| 蜜臀久久99精品久久久久久小说| 国产精品美女久久福利网站| 久久精品国产99久久丝袜| 国产午夜精品理论片久久影视 | 97久久精品人妻人人搡人人玩| 欧美与黑人午夜性猛交久久久| 品成人欧美大片久久国产欧美| 久久av无码专区亚洲av桃花岛| 久久无码AV中文出轨人妻| 精品国产日韩久久亚洲| 欧洲国产伦久久久久久久| 性做久久久久久久久久久| 久久久久久亚洲精品无码| 久久人人爽人人爽人人片AV麻豆| 久久这里只有精品久久| 91亚洲国产成人久久精品网址| 狠狠干狠狠久久| 久久亚洲欧美日本精品| 国产高潮国产高潮久久久91| 国内精品伊人久久久久影院对白| 777久久精品一区二区三区无码| 办公室久久精品| 日韩欧美亚洲国产精品字幕久久久| 久久久久无码精品国产app| 日韩AV毛片精品久久久|