Kurobeats

Hooking Windows API

Aug 21st, 2017
678
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 48.97 KB | None | 0 0
  1. ===========================[ Hooking Windows API ]==============================
  2.  
  3. Technics of hooking API functions on Windows
  4. --------------------------------------------
  5.  
  6. Author: Holy_Father <[email protected]>
  7. Version: 1.1 english
  8. Date: 6.10.2002
  9.  
  10.  
  11. =====[ 1. Contents ]============================================================
  12.  
  13. 1. Contents
  14. 2. Introduction
  15. 3. Hooking methods
  16. 3.1 Hooking before running
  17. 3.2 Hooking during running
  18. 3.2.1 Own process hooking using IAT
  19. 3.2.2 Own process hooking using entry point rewriting
  20. 3.2.3 Original function saving
  21. 3.2.4 Other process hooking
  22. 3.2.4.1 DLL Injection
  23. 3.2.4.2 Independent code
  24. 3.2.4.3 Raw change
  25. 4. Ending
  26.  
  27.  
  28. =====[ 2. Introduction ]========================================================
  29.  
  30. This text is about hooking API functions on OS Windows. All examples
  31. here completely works on Windows systems based on NT technology version NT 4.0
  32. and higher (Windows NT 4.0, Windows 2000, Windows XP). Probably will also work
  33. on others Windows systems.
  34. You should be familiar with processes on Windows, assembler, PE files
  35. structure and some API functions to understand whole text.
  36. When using term "Hooking API" here, I mean the full change of API.
  37. So, when calling hooked API, our code is run immediately. I do not deal with
  38. cases of API monitoring only. I will write about complete hooking.
  39.  
  40.  
  41. =====[ 3. Hooking methods ]=====================================================
  42.  
  43. Our goal is generally to replace the code of some function with our
  44. code. This problem can be sometimes solved before running the process. This can
  45. be done mostly with user level process which are run by us and the goal is e.g.
  46. to change the program behaviour. Example of this can be application crack.
  47. E.g. program which wants original CD-ROM during startup (this was in the game
  48. Atlantis) and we want to run it without CDs. If we change the function for
  49. getting a drive type we would be able to run this program from the hard drive.
  50. This can not be done or we do not want to do this when want to hook
  51. system process (e.g. services) or in the case we do not know which process will
  52. be the target. Then we will use hooking during running technic. Example of
  53. using this can be rootkit or virus with anti-antivirus technics.
  54.  
  55.  
  56. =====[ 3.1 Hooking before running ]=============================================
  57.  
  58. This is about physical module change (mostly .exe or .dll) when the
  59. function, which we want to change, is. We've got three possibilities at least
  60. here on how to do this.
  61. The first is to find entry point of that function and basically to
  62. rewrite its code. This is limited by the function size but we can load some
  63. other modules dynamically (API LoadLibrary), so it could be enought.
  64. Kernel functions (kernel32.dll) can be used in all cases because
  65. each process in windows has its own copy of this module. Other advantage
  66. is if we know on which OS will be changed module run. We can use direct
  67. pointers in this case for e.g. API LoadLibraryA. This is because the address
  68. of kernel module in memory is static in the scope of one OS Windows version.
  69. We can also use behaviour of dynamically loaded module. In this case its
  70. initialization part is run immediately after loading to the memory. We are not
  71. limited in initialization part of new module.
  72. Second possibility of replacing function in module is its extension.
  73. Then we have to choose between replacing first 5 bytes by relative jump
  74. or rewriting IAT. In the case of relative jump, this will redirect the code
  75. execution to our code. When calling function which IAT record is changed,
  76. our code will be executed directly after this call. But extension of the module
  77. is not so easy because we have to care about DLL header.
  78. Next one is replacing the whole module. That means we create own
  79. version of the module which can load the original one and call original
  80. functions which we are not interested in. But important functions will be
  81. totally new. This method is not so good for big modules which can contain
  82. hundreds of exports.
  83.  
  84.  
  85. =====[ 3.2 Hooking during running ]=============================================
  86.  
  87. Hooking before running is mostly very special and intimately oriented
  88. for concrete application (or module). If we replace function in kernel32.dll
  89. or in ntdll.dll (only on NT OS) we will get perfect replace of this function
  90. in all processes which will be run later, but it is so difficult to make it
  91. because we have to take care about accuracy and code prefection of new
  92. functions or whole new modules, but the main problem is that only process
  93. which will be run later will be hooked (so for all process we have to reboot
  94. system). Next problem could be access to these files because NT OS tries to
  95. protect them. Much more pretty solution is to hook process during running. This
  96. method require more knowledge but the result is perfect. Hooking during running
  97. can be done only on process for which we have writing access to their memory.
  98. For the writing in itself we will use API function WriteProcessMemory. We will
  99. start from hooking our own process during running.
  100.  
  101.  
  102. =====[ 3.2.1 Own process hooking using IAT ]====================================
  103.  
  104. There are many possibilities here. At first I will show you how to hook
  105. function by rewriting IAT. Following picture shows structure of PE file:
  106.  
  107. +-------------------------------+ - offset 0
  108. | MS DOS Header ("MZ") and stub |
  109. +-------------------------------+
  110. | PE signature ("PE") |
  111. +-------------------------------+
  112. | .text | - module code
  113. | Program Code |
  114. | |
  115. +-------------------------------+
  116. | .data | - initialized (global static) data
  117. | Initialized Data |
  118. | |
  119. +-------------------------------+
  120. | .idata | - information for imported functions
  121. | Import Table | and data
  122. | |
  123. +-------------------------------+
  124. | .edata | - information for exported functions
  125. | Export Table | and data
  126. | |
  127. +-------------------------------+
  128. | Debug symbols |
  129. +-------------------------------+
  130.  
  131. Important part for us here is Import Address Table (IAT) in the .idata
  132. part. This part contains description of imports and mainly imported functions
  133. addresses. Now it is important to know how are PE files created. When calling
  134. arbitrary API indirectly in programming language (that means we call it using
  135. its name, no using its OS specific address) the compiler does not link direct
  136. calls to the module but it links call to IAT on jmp instruction which will be
  137. filled by process loader while OS is loading process to the memory. This is why
  138. we can use the same binary on two different version os Windows where modules
  139. can be loaded to another addresses. Process loader will fill out direct jmp
  140. instructions in IAT which is used by our calls from the program code. So,
  141. if we are able to find out specific function in IAT which we want to hook,
  142. we can easily change jmp instruction there and redirect code to our address.
  143. Every call after doing this will execute our code. Advantage of this method
  144. is its perfection. Disadvantage is often amount of functions which should be
  145. hooked (e.g. if we want to change program behaviour in the file searching APIs
  146. we will have to change functions FindFirstFile and FindNextFile, but we have to
  147. know that these functions have its ANSI and WIDE version, so we have to change
  148. IAT address for FindFirstFileA, FindFirstFileW, FindNextFileA and also
  149. FileNextFileW. But there still some others like FindFirstFileExA and its WIDE
  150. version FindFirstFileExW which are called by previous mentioned functions.
  151. We know that FindFirstFileW calls FindFirstFileExW but this is done directly
  152. - not usinig IAT. And still some others to go. There are e.g. ShellAPI
  153. functions like SHGetDesktopFolder which also directly calls FindFirstFileW or
  154. FindFirstFileExW). But if we will get all of them, the result will be perfect.
  155. We can use ImageDirectoryEntryToData from imagehlp.dll to find out IAT
  156. easily.
  157.  
  158. PVOID ImageDirectoryEntryToData(
  159. IN LPVOID Base,
  160. IN BOOLEAN MappedAsImage,
  161. IN USHORT DirectoryEntry,
  162. OUT PULONG Size
  163. );
  164.  
  165. We will use Instance of our application as Base (Instance can be get by calling
  166. GetModuleHandle:
  167.  
  168. hInstance = GetModuleHandleA(NULL);
  169.  
  170. ), and as DirectoryEntry we will use constant IMAGE_DIRECTORY_ENTRY_IMPORT.
  171.  
  172. #define IMAGE_DIRECTORY_ENTRY_IMPORT 1
  173.  
  174. Result of this function is pointer to the first IAT record. IAT records are
  175. structures which are defined by I IMAGE_IMPORT_DESCRIPTOR. So, the result
  176. is a pointer on IMAGE_IMPORT_DESCRIPTOR.
  177.  
  178. typedef struct _IMAGE_THUNK_DATA {
  179. union {
  180. PBYTE ForwarderString;
  181. PDWORD Function;
  182. DWORD Ordinal;
  183. PIMAGE_IMPORT_BY_NAME AddressOfData;
  184. } ;
  185. } IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;
  186.  
  187. typedef struct _IMAGE_IMPORT_DESCRIPTOR {
  188. union {
  189. DWORD Characteristics;
  190. PIMAGE_THUNK_DATA OriginalFirstThunk;
  191. } ;
  192. DWORD TimeDateStamp;
  193. DWORD ForwarderChain;
  194. DWORD Name;
  195. PIMAGE_THUNK_DATA FirstThunk;
  196. } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;
  197.  
  198. The Name value in IMAGE_IMPORT_DESCRIPTOR is a relative reference to
  199. the name of module. If we want to hook a function e.g. from kernel32.dll
  200. we have to find out in imports which belongs to the descriptor with name
  201. kernel32.dll. We will call ImageDirectoryEntryToData at first and than we will
  202. try to find descriptor with name "kernel32.dll" (there can be more than one
  203. descriptor with this name). Finally we will have to find our function in
  204. the list of all functions in the record (address of our function can be get
  205. by GetProcAddress function). If we find it we must use VirtualProtect to change
  206. memory page protection and after then we can write to this part of memory.
  207. After rewriting the address we have to change the protection back. Before
  208. calling VirtualProtect we have to know some information about this memory page.
  209. This is done by VirtualQuery. We can add some tests in case some calls will
  210. fail (e.g. we will not continue if the first VirtualProtect call failed, etc)>
  211.  
  212. PCSTR pszHookModName = "kernel32.dll",pszSleepName = "Sleep";
  213. HMODULE hKernel = GetModuleHandle(pszHookModName);
  214. PROC pfnNew = (PROC)0x12345678, //new address will be here
  215. pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);
  216.  
  217. ULONG ulSize;
  218. PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
  219. (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
  220. hInstance,
  221. TRUE,
  222. IMAGE_DIRECTORY_ENTRY_IMPORT,
  223. &ulSize
  224. );
  225.  
  226. while (pImportDesc->Name)
  227. {
  228. PSTR pszModName = (PSTR)((PBYTE) hInstance + pImportDesc->Name);
  229. if (stricmp(pszModName, pszHookModName) == 0)
  230. break;
  231. pImportDesc++;
  232. }
  233.  
  234. PIMAGE_THUNK_DATA pThunk =
  235. (PIMAGE_THUNK_DATA)((PBYTE) hInstance + pImportDesc->FirstThunk);
  236.  
  237. while (pThunk->u1.Function)
  238. {
  239. PROC* ppfn = (PROC*) &pThunk->u1.Function;
  240. BOOL bFound = (*ppfn == pfnHookAPIAddr);
  241.  
  242. if (bFound)
  243. {
  244. MEMORY_BASIC_INFORMATION mbi;
  245. VirtualQuery(
  246. ppfn,
  247. &mbi,
  248. sizeof(MEMORY_BASIC_INFORMATION)
  249. );
  250. VirtualProtect(
  251. mbi.BaseAddress,
  252. mbi.RegionSize,
  253. PAGE_READWRITE,
  254. &mbi.Protect)
  255. )
  256.  
  257. *ppfn = *pfnNew;
  258.  
  259. DWORD dwOldProtect;
  260. VirtualProtect(
  261. mbi.BaseAddress,
  262. mbi.RegionSize,
  263. mbi.Protect,
  264. &dwOldProtect
  265. );
  266. break;
  267. }
  268. pThunk++;
  269. }
  270.  
  271. Result of calling Sleep(1000) can be for example this:
  272.  
  273. 00407BD8: 68E8030000 push 0000003E8h
  274. 00407BDD: E812FAFFFF call Sleep
  275.  
  276. Sleep: ;this is jump on address in IAT
  277. 004075F4: FF25BCA14000 jmp dword ptr [00040A1BCh]
  278.  
  279. original table:
  280. 0040A1BC: 79 67 E8 77 00 00 00 00
  281.  
  282. new table:
  283. 0040A1BC: 78 56 34 12 00 00 00 00
  284.  
  285. So the final jump is to 0x12345678.
  286.  
  287.  
  288. =====[ 3.2.2 Own process hooking using entry point rewriting ]==================
  289.  
  290. The method of rewriting first few instructions on the function entry
  291. point is realy simple. As in the case of rewritng address in IAT we have to
  292. change a page protection at first. Here it will be first 5 bytes of the given
  293. function which we want to hook. For later usage we will use dynamical alocation
  294. of MEMORY_BASIC_INFORMATION structure. The beginning of the function is get
  295. by GetProcAddress again. On this address we will insert relative jump to our
  296. code. Following program calls Sleep(5000) (so it will wait for 5 seconds), than
  297. the Sleep functions is hooked and redirected to new_sleep, finally it calls
  298. Sleep(5000) again. Because new function new_sleep does nothing and returns
  299. immediately the whole program will take only 5 in place of 10 seconds.
  300.  
  301.  
  302. .386p
  303. .model flat, stdcall
  304.  
  305. includelib lib\kernel32.lib
  306. Sleep PROTO :DWORD
  307. GetModuleHandleA PROTO :DWORD
  308. GetProcAddress PROTO :DWORD,:DWORD
  309. VirtualQuery PROTO :DWORD,:DWORD,:DWORD
  310. VirtualProtect PROTO :DWORD,:DWORD,:DWORD,:DWORD
  311. VirtualAlloc PROTO :DWORD,:DWORD,:DWORD,:DWORD
  312. VirtualFree PROTO :DWORD,:DWORD,:DWORD
  313. FlushInstructionCache PROTO :DWORD,:DWORD,:DWORD
  314. GetCurrentProcess PROTO
  315. ExitProcess PROTO :DWORD
  316.  
  317.  
  318. .data
  319.  
  320. kernel_name db "kernel32.dll",0
  321. sleep_name db "Sleep",0
  322. old_protect dd ?
  323.  
  324. MEMORY_BASIC_INFORMATION_SIZE equ 28
  325.  
  326. PAGE_READWRITE dd 000000004h
  327. PAGE_EXECUTE_READWRITE dd 000000040h
  328. MEM_COMMIT dd 000001000h
  329. MEM_RELEASE dd 000008000h
  330.  
  331.  
  332. .code
  333. start:
  334. push 5000
  335. call Sleep
  336.  
  337. do_hook:
  338. push offset kernel_name
  339. call GetModuleHandleA
  340. push offset sleep_name
  341. push eax
  342. call GetProcAddress
  343. mov edi,eax ;finally got Sleep address
  344.  
  345. push PAGE_READWRITE
  346. push MEM_COMMIT
  347. push MEMORY_BASIC_INFORMATION_SIZE
  348. push 0
  349. call VirtualAlloc
  350. test eax,eax
  351. jz do_sleep
  352. mov esi,eax ;alocation for MBI
  353.  
  354. push MEMORY_BASIC_INFORMATION_SIZE
  355. push esi
  356. push edi
  357. call VirtualQuery ;inforamtion about the memory page
  358. test eax,eax
  359. jz free_mem
  360.  
  361. call GetCurrentProcess
  362. push 5
  363. push edi
  364. push eax
  365. call FlushInstructionCache ;just to be sure :)
  366.  
  367. lea eax,[esi+014h]
  368. push eax
  369. push PAGE_EXECUTE_READWRITE
  370. lea eax,[esi+00Ch]
  371. push [eax]
  372. push [esi]
  373. call VirtualProtect ;we will change protection for a moment
  374. ;so we will be able to write there
  375. test eax,eax
  376. jz free_mem
  377.  
  378. mov byte ptr [edi],0E9h ;to write relative jump
  379. mov eax,offset new_sleep
  380. sub eax,edi
  381. sub eax,5
  382. inc edi
  383. stosd ;this is relative address for jump
  384.  
  385. push offset old_protect
  386. lea eax,[esi+014h]
  387. push [eax]
  388. lea eax,[esi+00Ch]
  389. push [eax]
  390. push [esi]
  391. call VirtualProtect ;return back the protection of page
  392.  
  393. free_mem:
  394. push MEM_RELEASE
  395. push 0
  396. push esi
  397. call VirtualFree ;free memory
  398. do_sleep:
  399. push 5000
  400. call Sleep
  401. push 0
  402. call ExitProcess
  403. new_sleep:
  404. ret 004h
  405. end start
  406.  
  407.  
  408. Result of the second call Sleep is this:
  409.  
  410. 004010A4: 6888130000 push 000001388h
  411. 004010A9: E80A000000 call Sleep
  412.  
  413.  
  414. Sleep: ;toto je jump na adresu v IAT
  415. 004010B8: FF2514204000 jmp dword ptr [000402014h]
  416.  
  417. tabulka:
  418. 00402014: 79 67 E8 77 6C 7D E8 77
  419.  
  420. Kernel32.Sleep:
  421. 77E86779: E937A95788 jmp 0004010B5h
  422.  
  423. new_sleep:
  424. 004010B5: C20400 ret 004h
  425.  
  426.  
  427. =====[ 3.2.3 Original function saving ]=========================================
  428.  
  429. Mostly we need more than a function hook. For example in case when we
  430. don't want to replace the given function but only to check its result, or in
  431. case when we want to replace the function only sometimes e.g. when it is called
  432. with specific arguments. Good example of this is already mentioned files hiding
  433. done by replacing FindXXXFile functions. So if we want to hide specific files
  434. and don't want to be noticeable we have to leave original function for all
  435. other files without changing the functions behavior. This is simple when using
  436. method of rewriting IAT. For calling original function we can get its original
  437. address with GetProcAddress and then call it directly. But the problem occurs
  438. when using rewriting entry point method. By rewriting those 5 bytes at the
  439. functions entry point we lost original function irrecoverably. So we need to
  440. save first instructions. We can use following technic.
  441. We know we will rewrite only first 5 bytes but don't know how many
  442. instructions there are or how long they are. We have to reserve enough memory
  443. for first instructions. 16 bytes could be enought because there are usually not
  444. long instructions at the begin of function. Probably we can use less then 16.
  445. Whole reserverd memory will be filled with 0x90 (0x90 = nop) in case there
  446. are shorter instructions. Next 5 bytes will be relative jump which will be
  447. filled later.
  448.  
  449. old_hook: db 090h,090h,090h,090h,090h,090h,090h,090h
  450. db 090h,090h,090h,090h,090h,090h,090h,090h
  451. db 0E9h,000h,000h,000h,000h
  452.  
  453.  
  454. Now we are ready to copy first instructions. It is a long stuff to get
  455. instruction length, this is why we will work with the complete engine. This
  456. was made by Z0MBiE. Input argument is instruction address for which we want to
  457. get length. Output is commonly in eax.
  458.  
  459.  
  460. ; LDE32, Length-Disassembler Engine, 32-bit, (x) 1999-2000 Z0MBiE
  461. ; special edition for REVERT tool
  462.  
  463. ; version 1.05
  464.  
  465. C_MEM1 equ 0001h ; |
  466. C_MEM2 equ 0002h ; |may be used simultaneously
  467. C_MEM4 equ 0004h ; |
  468. C_DATA1 equ 0100h ; |
  469. C_DATA2 equ 0200h ; |may be used simultaneously
  470. C_DATA4 equ 0400h ; |
  471. C_67 equ 0010h ; used with C_PREFIX
  472. C_MEM67 equ 0020h ; C_67 ? C_MEM2 : C_MEM4
  473. C_66 equ 1000h ; used with C_PREFIX
  474. C_DATA66 equ 2000h ; C_66 ? C_DATA2 : C_DATA4
  475. C_PREFIX equ 0008h ; prefix. take opcode again
  476. C_MODRM equ 4000h ; MODxxxR/M
  477. C_DATAW0 equ 8000h ; opc&1 ? C_DATA66 : C_DATA1
  478.  
  479. p386
  480. model flat
  481. locals @@
  482.  
  483. .code
  484.  
  485. public disasm_main
  486. public _disasm_main
  487. public @disasm_main
  488. public DISASM_MAIN
  489.  
  490. disasm_main:
  491. _disasm_main:
  492. @disasm_main:
  493. DISASM_MAIN:
  494.  
  495. ; returns opcode length in EAX or -1 if error
  496.  
  497. ; input: pointer to opcode
  498.  
  499. ; __fastcall EAX
  500. ; __cdecl [ESP+4]
  501.  
  502. ;this is my first change here, it's the label only for calling this function
  503. get_instr_len:
  504.  
  505. mov ecx, [esp+4] ; ECX = opcode ptr
  506.  
  507. xor edx, edx ; flags
  508. xor eax, eax
  509.  
  510. @@prefix: and dl, not C_PREFIX
  511.  
  512. mov al, [ecx]
  513. inc ecx
  514.  
  515. or edx, table_1[eax*4]
  516.  
  517. test dl, C_PREFIX
  518. jnz @@prefix
  519.  
  520. cmp al, 0F6h
  521. je @@test
  522. cmp al, 0F7h
  523. je @@test
  524.  
  525. cmp al, 0CDh
  526. je @@int
  527.  
  528. cmp al, 0Fh
  529. je @@0F
  530. @@cont:
  531. test dh, C_DATAW0 shr 8
  532. jnz @@dataw0
  533. @@dataw0done:
  534. test dh, C_MODRM shr 8
  535. jnz @@modrm
  536. @@exitmodrm:
  537. test dl, C_MEM67
  538. jnz @@mem67
  539. @@mem67done:
  540. test dh, C_DATA66 shr 8
  541. jnz @@data66
  542. @@data66done:
  543. mov eax, ecx
  544. sub eax, [esp+4]
  545.  
  546. and edx,C_MEM1+C_MEM2+C_MEM4+C_DATA1+C_DATA2+C_DATA4
  547. add al, dl
  548. add al, dh
  549.  
  550. ;my second change heer, there was retn only in original version
  551. @@exit: ret 00004h
  552.  
  553. @@test: or dh, C_MODRM shr 8
  554. test byte ptr [ecx], 00111000b ; F6/F7 -- test
  555. jnz @@cont
  556. or dh, C_DATAW0 shr 8
  557. jmp @@cont
  558.  
  559. @@int: or dh, C_DATA1 shr 8
  560. cmp byte ptr [ecx], 20h
  561. jne @@cont
  562. or dh, C_DATA4 shr 8
  563. jmp @@cont
  564.  
  565. @@0F: mov al, [ecx]
  566. inc ecx
  567. or edx, table_0F[eax*4]
  568.  
  569. cmp edx, -1
  570. jne @@cont
  571.  
  572. @@error: mov eax, edx
  573. jmp @@exit
  574.  
  575. @@dataw0: xor dh, C_DATA66 shr 8
  576. test al, 00000001b
  577. jnz @@dataw0done
  578. xor dh, (C_DATA66+C_DATA1) shr 8
  579. jmp @@dataw0done
  580.  
  581. @@mem67: xor dl, C_MEM2
  582. test dl, C_67
  583. jnz @@mem67done
  584. xor dl, C_MEM4+C_MEM2
  585. jmp @@mem67done
  586.  
  587. @@data66: xor dh, C_DATA2 shr 8
  588. test dh, C_66 shr 8
  589. jnz @@data66done
  590. xor dh, (C_DATA4+C_DATA2) shr 8
  591. jmp @@data66done
  592.  
  593. @@modrm: mov al, [ecx]
  594. inc ecx
  595.  
  596. mov ah, al ; ah=mod, al=rm
  597.  
  598. and ax, 0C007h
  599. cmp ah, 0C0h
  600. je @@exitmodrm
  601.  
  602. test dl, C_67
  603. jnz @@modrm16
  604.  
  605. @@modrm32: cmp al, 04h
  606. jne @@a
  607.  
  608. mov al, [ecx] ; sib
  609. inc ecx
  610. and al, 07h
  611.  
  612. @@a: cmp ah, 40h
  613. je @@mem1
  614. cmp ah, 80h
  615. je @@mem4
  616.  
  617. cmp ax, 0005h
  618. jne @@exitmodrm
  619.  
  620. @@mem4: or dl, C_MEM4
  621. jmp @@exitmodrm
  622.  
  623. @@mem1: or dl, C_MEM1
  624. jmp @@exitmodrm
  625.  
  626. @@modrm16: cmp ax, 0006h
  627. je @@mem2
  628. cmp ah, 40h
  629. je @@mem1
  630. cmp ah, 80h
  631. jne @@exitmodrm
  632.  
  633. @@mem2: or dl, C_MEM2
  634. jmp @@exitmodrm
  635.  
  636. endp
  637.  
  638. .data
  639.  
  640. ;0F -- analyzed in code, no flags (i.e.flags must be 0)
  641. ;F6,F7 -- --//-- (ttt=000 -- 3 bytes, otherwise 2 bytes)
  642. ;CD -- --//-- (6 bytes if CD 20, 2 bytes otherwise)
  643.  
  644. table_1 label dword ; normal instructions
  645.  
  646. dd C_MODRM ; 00
  647. dd C_MODRM ; 01
  648. dd C_MODRM ; 02
  649. dd C_MODRM ; 03
  650. dd C_DATAW0 ; 04
  651. dd C_DATAW0 ; 05
  652. dd 0 ; 06
  653. dd 0 ; 07
  654. dd C_MODRM ; 08
  655. dd C_MODRM ; 09
  656. dd C_MODRM ; 0A
  657. dd C_MODRM ; 0B
  658. dd C_DATAW0 ; 0C
  659. dd C_DATAW0 ; 0D
  660. dd 0 ; 0E
  661. dd 0 ; 0F
  662. dd C_MODRM ; 10
  663. dd C_MODRM ; 11
  664. dd C_MODRM ; 12
  665. dd C_MODRM ; 13
  666. dd C_DATAW0 ; 14
  667. dd C_DATAW0 ; 15
  668. dd 0 ; 16
  669. dd 0 ; 17
  670. dd C_MODRM ; 18
  671. dd C_MODRM ; 19
  672. dd C_MODRM ; 1A
  673. dd C_MODRM ; 1B
  674. dd C_DATAW0 ; 1C
  675. dd C_DATAW0 ; 1D
  676. dd 0 ; 1E
  677. dd 0 ; 1F
  678. dd C_MODRM ; 20
  679. dd C_MODRM ; 21
  680. dd C_MODRM ; 22
  681. dd C_MODRM ; 23
  682. dd C_DATAW0 ; 24
  683. dd C_DATAW0 ; 25
  684. dd C_PREFIX ; 26
  685. dd 0 ; 27
  686. dd C_MODRM ; 28
  687. dd C_MODRM ; 29
  688. dd C_MODRM ; 2A
  689. dd C_MODRM ; 2B
  690. dd C_DATAW0 ; 2C
  691. dd C_DATAW0 ; 2D
  692. dd C_PREFIX ; 2E
  693. dd 0 ; 2F
  694. dd C_MODRM ; 30
  695. dd C_MODRM ; 31
  696. dd C_MODRM ; 32
  697. dd C_MODRM ; 33
  698. dd C_DATAW0 ; 34
  699. dd C_DATAW0 ; 35
  700. dd C_PREFIX ; 36
  701. dd 0 ; 37
  702. dd C_MODRM ; 38
  703. dd C_MODRM ; 39
  704. dd C_MODRM ; 3A
  705. dd C_MODRM ; 3B
  706. dd C_DATAW0 ; 3C
  707. dd C_DATAW0 ; 3D
  708. dd C_PREFIX ; 3E
  709. dd 0 ; 3F
  710. dd 0 ; 40
  711. dd 0 ; 41
  712. dd 0 ; 42
  713. dd 0 ; 43
  714. dd 0 ; 44
  715. dd 0 ; 45
  716. dd 0 ; 46
  717. dd 0 ; 47
  718. dd 0 ; 48
  719. dd 0 ; 49
  720. dd 0 ; 4A
  721. dd 0 ; 4B
  722. dd 0 ; 4C
  723. dd 0 ; 4D
  724. dd 0 ; 4E
  725. dd 0 ; 4F
  726. dd 0 ; 50
  727. dd 0 ; 51
  728. dd 0 ; 52
  729. dd 0 ; 53
  730. dd 0 ; 54
  731. dd 0 ; 55
  732. dd 0 ; 56
  733. dd 0 ; 57
  734. dd 0 ; 58
  735. dd 0 ; 59
  736. dd 0 ; 5A
  737. dd 0 ; 5B
  738. dd 0 ; 5C
  739. dd 0 ; 5D
  740. dd 0 ; 5E
  741. dd 0 ; 5F
  742. dd 0 ; 60
  743. dd 0 ; 61
  744. dd C_MODRM ; 62
  745. dd C_MODRM ; 63
  746. dd C_PREFIX ; 64
  747. dd C_PREFIX ; 65
  748. dd C_PREFIX+C_66 ; 66
  749. dd C_PREFIX+C_67 ; 67
  750. dd C_DATA66 ; 68
  751. dd C_MODRM+C_DATA66 ; 69
  752. dd C_DATA1 ; 6A
  753. dd C_MODRM+C_DATA1 ; 6B
  754. dd 0 ; 6C
  755. dd 0 ; 6D
  756. dd 0 ; 6E
  757. dd 0 ; 6F
  758. dd C_DATA1 ; 70
  759. dd C_DATA1 ; 71
  760. dd C_DATA1 ; 72
  761. dd C_DATA1 ; 73
  762. dd C_DATA1 ; 74
  763. dd C_DATA1 ; 75
  764. dd C_DATA1 ; 76
  765. dd C_DATA1 ; 77
  766. dd C_DATA1 ; 78
  767. dd C_DATA1 ; 79
  768. dd C_DATA1 ; 7A
  769. dd C_DATA1 ; 7B
  770. dd C_DATA1 ; 7C
  771. dd C_DATA1 ; 7D
  772. dd C_DATA1 ; 7E
  773. dd C_DATA1 ; 7F
  774. dd C_MODRM+C_DATA1 ; 80
  775. dd C_MODRM+C_DATA66 ; 81
  776. dd C_MODRM+C_DATA1 ; 82
  777. dd C_MODRM+C_DATA1 ; 83
  778. dd C_MODRM ; 84
  779. dd C_MODRM ; 85
  780. dd C_MODRM ; 86
  781. dd C_MODRM ; 87
  782. dd C_MODRM ; 88
  783. dd C_MODRM ; 89
  784. dd C_MODRM ; 8A
  785. dd C_MODRM ; 8B
  786. dd C_MODRM ; 8C
  787. dd C_MODRM ; 8D
  788. dd C_MODRM ; 8E
  789. dd C_MODRM ; 8F
  790. dd 0 ; 90
  791. dd 0 ; 91
  792. dd 0 ; 92
  793. dd 0 ; 93
  794. dd 0 ; 94
  795. dd 0 ; 95
  796. dd 0 ; 96
  797. dd 0 ; 97
  798. dd 0 ; 98
  799. dd 0 ; 99
  800. dd C_DATA66+C_MEM2 ; 9A
  801. dd 0 ; 9B
  802. dd 0 ; 9C
  803. dd 0 ; 9D
  804. dd 0 ; 9E
  805. dd 0 ; 9F
  806. dd C_MEM67 ; A0
  807. dd C_MEM67 ; A1
  808. dd C_MEM67 ; A2
  809. dd C_MEM67 ; A3
  810. dd 0 ; A4
  811. dd 0 ; A5
  812. dd 0 ; A6
  813. dd 0 ; A7
  814. dd C_DATA1 ; A8
  815. dd C_DATA66 ; A9
  816. dd 0 ; AA
  817. dd 0 ; AB
  818. dd 0 ; AC
  819. dd 0 ; AD
  820. dd 0 ; AE
  821. dd 0 ; AF
  822. dd C_DATA1 ; B0
  823. dd C_DATA1 ; B1
  824. dd C_DATA1 ; B2
  825. dd C_DATA1 ; B3
  826. dd C_DATA1 ; B4
  827. dd C_DATA1 ; B5
  828. dd C_DATA1 ; B6
  829. dd C_DATA1 ; B7
  830. dd C_DATA66 ; B8
  831. dd C_DATA66 ; B9
  832. dd C_DATA66 ; BA
  833. dd C_DATA66 ; BB
  834. dd C_DATA66 ; BC
  835. dd C_DATA66 ; BD
  836. dd C_DATA66 ; BE
  837. dd C_DATA66 ; BF
  838. dd C_MODRM+C_DATA1 ; C0
  839. dd C_MODRM+C_DATA1 ; C1
  840. dd C_DATA2 ; C2
  841. dd 0 ; C3
  842. dd C_MODRM ; C4
  843. dd C_MODRM ; C5
  844. dd C_MODRM+C_DATA1 ; C6
  845. dd C_MODRM+C_DATA66 ; C7
  846. dd C_DATA2+C_DATA1 ; C8
  847. dd 0 ; C9
  848. dd C_DATA2 ; CA
  849. dd 0 ; CB
  850. dd 0 ; CC
  851. dd 0 ; CD
  852. dd 0 ; CE
  853. dd 0 ; CF
  854. dd C_MODRM ; D0
  855. dd C_MODRM ; D1
  856. dd C_MODRM ; D2
  857. dd C_MODRM ; D3
  858. dd C_DATA1 ; D4
  859. dd C_DATA1 ; D5
  860. dd 0 ; D6
  861. dd 0 ; D7
  862. dd C_MODRM ; D8
  863. dd C_MODRM ; D9
  864. dd C_MODRM ; DA
  865. dd C_MODRM ; DB
  866. dd C_MODRM ; DC
  867. dd C_MODRM ; DD
  868. dd C_MODRM ; DE
  869. dd C_MODRM ; DF
  870. dd C_DATA1 ; E0
  871. dd C_DATA1 ; E1
  872. dd C_DATA1 ; E2
  873. dd C_DATA1 ; E3
  874. dd C_DATA1 ; E4
  875. dd C_DATA1 ; E5
  876. dd C_DATA1 ; E6
  877. dd C_DATA1 ; E7
  878. dd C_DATA66 ; E8
  879. dd C_DATA66 ; E9
  880. dd C_DATA66+C_MEM2 ; EA
  881. dd C_DATA1 ; EB
  882. dd 0 ; EC
  883. dd 0 ; ED
  884. dd 0 ; EE
  885. dd 0 ; EF
  886. dd C_PREFIX ; F0
  887. dd 0 ; F1
  888. dd C_PREFIX ; F2
  889. dd C_PREFIX ; F3
  890. dd 0 ; F4
  891. dd 0 ; F5
  892. dd 0 ; F6
  893. dd 0 ; F7
  894. dd 0 ; F8
  895. dd 0 ; F9
  896. dd 0 ; FA
  897. dd 0 ; FB
  898. dd 0 ; FC
  899. dd 0 ; FD
  900. dd C_MODRM ; FE
  901. dd C_MODRM ; FF
  902.  
  903. table_0F label dword ; 0F-prefixed instructions
  904.  
  905. dd C_MODRM ; 00
  906. dd C_MODRM ; 01
  907. dd C_MODRM ; 02
  908. dd C_MODRM ; 03
  909. dd -1 ; 04
  910. dd -1 ; 05
  911. dd 0 ; 06
  912. dd -1 ; 07
  913. dd 0 ; 08
  914. dd 0 ; 09
  915. dd 0 ; 0A
  916. dd 0 ; 0B
  917. dd -1 ; 0C
  918. dd -1 ; 0D
  919. dd -1 ; 0E
  920. dd -1 ; 0F
  921. dd -1 ; 10
  922. dd -1 ; 11
  923. dd -1 ; 12
  924. dd -1 ; 13
  925. dd -1 ; 14
  926. dd -1 ; 15
  927. dd -1 ; 16
  928. dd -1 ; 17
  929. dd -1 ; 18
  930. dd -1 ; 19
  931. dd -1 ; 1A
  932. dd -1 ; 1B
  933. dd -1 ; 1C
  934. dd -1 ; 1D
  935. dd -1 ; 1E
  936. dd -1 ; 1F
  937. dd -1 ; 20
  938. dd -1 ; 21
  939. dd -1 ; 22
  940. dd -1 ; 23
  941. dd -1 ; 24
  942. dd -1 ; 25
  943. dd -1 ; 26
  944. dd -1 ; 27
  945. dd -1 ; 28
  946. dd -1 ; 29
  947. dd -1 ; 2A
  948. dd -1 ; 2B
  949. dd -1 ; 2C
  950. dd -1 ; 2D
  951. dd -1 ; 2E
  952. dd -1 ; 2F
  953. dd -1 ; 30
  954. dd -1 ; 31
  955. dd -1 ; 32
  956. dd -1 ; 33
  957. dd -1 ; 34
  958. dd -1 ; 35
  959. dd -1 ; 36
  960. dd -1 ; 37
  961. dd -1 ; 38
  962. dd -1 ; 39
  963. dd -1 ; 3A
  964. dd -1 ; 3B
  965. dd -1 ; 3C
  966. dd -1 ; 3D
  967. dd -1 ; 3E
  968. dd -1 ; 3F
  969. dd -1 ; 40
  970. dd -1 ; 41
  971. dd -1 ; 42
  972. dd -1 ; 43
  973. dd -1 ; 44
  974. dd -1 ; 45
  975. dd -1 ; 46
  976. dd -1 ; 47
  977. dd -1 ; 48
  978. dd -1 ; 49
  979. dd -1 ; 4A
  980. dd -1 ; 4B
  981. dd -1 ; 4C
  982. dd -1 ; 4D
  983. dd -1 ; 4E
  984. dd -1 ; 4F
  985. dd -1 ; 50
  986. dd -1 ; 51
  987. dd -1 ; 52
  988. dd -1 ; 53
  989. dd -1 ; 54
  990. dd -1 ; 55
  991. dd -1 ; 56
  992. dd -1 ; 57
  993. dd -1 ; 58
  994. dd -1 ; 59
  995. dd -1 ; 5A
  996. dd -1 ; 5B
  997. dd -1 ; 5C
  998. dd -1 ; 5D
  999. dd -1 ; 5E
  1000. dd -1 ; 5F
  1001. dd -1 ; 60
  1002. dd -1 ; 61
  1003. dd -1 ; 62
  1004. dd -1 ; 63
  1005. dd -1 ; 64
  1006. dd -1 ; 65
  1007. dd -1 ; 66
  1008. dd -1 ; 67
  1009. dd -1 ; 68
  1010. dd -1 ; 69
  1011. dd -1 ; 6A
  1012. dd -1 ; 6B
  1013. dd -1 ; 6C
  1014. dd -1 ; 6D
  1015. dd -1 ; 6E
  1016. dd -1 ; 6F
  1017. dd -1 ; 70
  1018. dd -1 ; 71
  1019. dd -1 ; 72
  1020. dd -1 ; 73
  1021. dd -1 ; 74
  1022. dd -1 ; 75
  1023. dd -1 ; 76
  1024. dd -1 ; 77
  1025. dd -1 ; 78
  1026. dd -1 ; 79
  1027. dd -1 ; 7A
  1028. dd -1 ; 7B
  1029. dd -1 ; 7C
  1030. dd -1 ; 7D
  1031. dd -1 ; 7E
  1032. dd -1 ; 7F
  1033. dd C_DATA66 ; 80
  1034. dd C_DATA66 ; 81
  1035. dd C_DATA66 ; 82
  1036. dd C_DATA66 ; 83
  1037. dd C_DATA66 ; 84
  1038. dd C_DATA66 ; 85
  1039. dd C_DATA66 ; 86
  1040. dd C_DATA66 ; 87
  1041. dd C_DATA66 ; 88
  1042. dd C_DATA66 ; 89
  1043. dd C_DATA66 ; 8A
  1044. dd C_DATA66 ; 8B
  1045. dd C_DATA66 ; 8C
  1046. dd C_DATA66 ; 8D
  1047. dd C_DATA66 ; 8E
  1048. dd C_DATA66 ; 8F
  1049. dd C_MODRM ; 90
  1050. dd C_MODRM ; 91
  1051. dd C_MODRM ; 92
  1052. dd C_MODRM ; 93
  1053. dd C_MODRM ; 94
  1054. dd C_MODRM ; 95
  1055. dd C_MODRM ; 96
  1056. dd C_MODRM ; 97
  1057. dd C_MODRM ; 98
  1058. dd C_MODRM ; 99
  1059. dd C_MODRM ; 9A
  1060. dd C_MODRM ; 9B
  1061. dd C_MODRM ; 9C
  1062. dd C_MODRM ; 9D
  1063. dd C_MODRM ; 9E
  1064. dd C_MODRM ; 9F
  1065. dd 0 ; A0
  1066. dd 0 ; A1
  1067. dd 0 ; A2
  1068. dd C_MODRM ; A3
  1069. dd C_MODRM+C_DATA1 ; A4
  1070. dd C_MODRM ; A5
  1071. dd -1 ; A6
  1072. dd -1 ; A7
  1073. dd 0 ; A8
  1074. dd 0 ; A9
  1075. dd 0 ; AA
  1076. dd C_MODRM ; AB
  1077. dd C_MODRM+C_DATA1 ; AC
  1078. dd C_MODRM ; AD
  1079. dd -1 ; AE
  1080. dd C_MODRM ; AF
  1081. dd C_MODRM ; B0
  1082. dd C_MODRM ; B1
  1083. dd C_MODRM ; B2
  1084. dd C_MODRM ; B3
  1085. dd C_MODRM ; B4
  1086. dd C_MODRM ; B5
  1087. dd C_MODRM ; B6
  1088. dd C_MODRM ; B7
  1089. dd -1 ; B8
  1090. dd -1 ; B9
  1091. dd C_MODRM+C_DATA1 ; BA
  1092. dd C_MODRM ; BB
  1093. dd C_MODRM ; BC
  1094. dd C_MODRM ; BD
  1095. dd C_MODRM ; BE
  1096. dd C_MODRM ; BF
  1097. dd C_MODRM ; C0
  1098. dd C_MODRM ; C1
  1099. dd -1 ; C2
  1100. dd -1 ; C3
  1101. dd -1 ; C4
  1102. dd -1 ; C5
  1103. dd -1 ; C6
  1104. dd -1 ; C7
  1105. dd 0 ; C8
  1106. dd 0 ; C9
  1107. dd 0 ; CA
  1108. dd 0 ; CB
  1109. dd 0 ; CC
  1110. dd 0 ; CD
  1111. dd 0 ; CE
  1112. dd 0 ; CF
  1113. dd -1 ; D0
  1114. dd -1 ; D1
  1115. dd -1 ; D2
  1116. dd -1 ; D3
  1117. dd -1 ; D4
  1118. dd -1 ; D5
  1119. dd -1 ; D6
  1120. dd -1 ; D7
  1121. dd -1 ; D8
  1122. dd -1 ; D9
  1123. dd -1 ; DA
  1124. dd -1 ; DB
  1125. dd -1 ; DC
  1126. dd -1 ; DD
  1127. dd -1 ; DE
  1128. dd -1 ; DF
  1129. dd -1 ; E0
  1130. dd -1 ; E1
  1131. dd -1 ; E2
  1132. dd -1 ; E3
  1133. dd -1 ; E4
  1134. dd -1 ; E5
  1135. dd -1 ; E6
  1136. dd -1 ; E7
  1137. dd -1 ; E8
  1138. dd -1 ; E9
  1139. dd -1 ; EA
  1140. dd -1 ; EB
  1141. dd -1 ; EC
  1142. dd -1 ; ED
  1143. dd -1 ; EE
  1144. dd -1 ; EF
  1145. dd -1 ; F0
  1146. dd -1 ; F1
  1147. dd -1 ; F2
  1148. dd -1 ; F3
  1149. dd -1 ; F4
  1150. dd -1 ; F5
  1151. dd -1 ; F6
  1152. dd -1 ; F7
  1153. dd -1 ; F8
  1154. dd -1 ; F9
  1155. dd -1 ; FA
  1156. dd -1 ; FB
  1157. dd -1 ; FC
  1158. dd -1 ; FD
  1159. dd -1 ; FE
  1160. dd -1 ; FF
  1161.  
  1162. end
  1163.  
  1164.  
  1165. Now we are able to get instruction length on arbitrary address. We will
  1166. repeat this call until 5 bytes are read. After this we will copy these bytes
  1167. to old_hook. We know how long are first instructions, so we can fill out the
  1168. relative jump address on the next instruction in original function.
  1169.  
  1170. .386p
  1171. .model flat, stdcall
  1172.  
  1173. ...
  1174.  
  1175. .data
  1176.  
  1177. kernel_name db "kernel32.dll",0
  1178. sleep_name db "Sleep",0
  1179.  
  1180. ...
  1181.  
  1182. MEM_RELEASE dd 000008000h
  1183.  
  1184. ;16 nops + one relative jump
  1185. old_sleep db 090h,090h,090h,090h,090h,090h,090h,090h,
  1186. 090h,090h,090h,090h,090h,090h,090h,090h,
  1187. 0E9h,000h,000h,000h,000h
  1188.  
  1189.  
  1190. .code
  1191. start:
  1192. push 5000
  1193. call Sleep
  1194.  
  1195. do_hook:
  1196. push offset kernel_name
  1197. call GetModuleHandleA
  1198. push offset sleep_name
  1199. push eax
  1200. call GetProcAddress
  1201. push eax
  1202. mov esi,eax
  1203.  
  1204. xor ecx,ecx
  1205. mov ebx,esi
  1206. get_five_bytes:
  1207. push ecx
  1208. push ebx
  1209. call get_instr_len ;calling LDE32
  1210. pop ecx
  1211. add ecx,eax
  1212. add ebx,eax
  1213. cmp ecx,5
  1214. jb get_five_bytes
  1215. mov edi,offset old_sleep ;counting relative jump address
  1216. mov [edi+011h],ebx
  1217. sub [edi+011h],edi
  1218. sub dword ptr [edi+011h],015h
  1219. rep movsb
  1220. pop edi
  1221.  
  1222. ;following code was above, so without comments
  1223.  
  1224. push PAGE_READWRITE
  1225. push MEM_COMMIT
  1226. push MEMORY_BASIC_INFORMATION_SIZE
  1227. push 0
  1228. call VirtualAlloc
  1229. test eax,eax
  1230. jz do_sleep
  1231. mov esi,eax
  1232.  
  1233. push MEMORY_BASIC_INFORMATION_SIZE
  1234. push esi
  1235. push edi
  1236. call VirtualQuery
  1237. test eax,eax
  1238. jz free_mem
  1239.  
  1240. call GetCurrentProcess
  1241. push 5
  1242. push edi
  1243. push eax
  1244. call FlushInstructionCache
  1245.  
  1246. lea eax,[esi+014h]
  1247. push eax
  1248. push PAGE_EXECUTE_READWRITE
  1249. lea eax,[esi+00Ch]
  1250. push [eax]
  1251. push [esi]
  1252. call VirtualProtect
  1253. test eax,eax
  1254. jz free_mem
  1255.  
  1256. mov byte ptr [edi],0E9h
  1257. mov eax,offset new_sleep
  1258. sub eax,edi
  1259. sub eax,5
  1260. inc edi
  1261. stosd
  1262.  
  1263. push offset old_protect
  1264. lea eax,[esi+014h]
  1265. push [eax]
  1266. lea eax,[esi+00Ch]
  1267. push [eax]
  1268. push [esi]
  1269. call VirtualProtect
  1270.  
  1271. free_mem:
  1272. push MEM_RELEASE
  1273. push 0
  1274. push esi
  1275. call VirtualFree
  1276. do_sleep:
  1277. push 5000
  1278. call Sleep
  1279. push 0
  1280. call ExitProcess
  1281. new_sleep:
  1282. mov eax,dword ptr [esp+004h]
  1283. add eax,eax ;doubling timeout
  1284. push eax
  1285. mov eax,offset old_sleep ;calling old function
  1286. call eax
  1287. ret 004h
  1288.  
  1289.  
  1290.  
  1291. After the hook it will look like this:
  1292.  
  1293. 004010CC: 6888130000 push 000001388h
  1294. 004010D1: E818090000 call Sleep
  1295.  
  1296.  
  1297. Sleep: ;this is jump on address in IAT
  1298. 004019EE: FF2514204000 jmp dword ptr [000402014h]
  1299.  
  1300. tabulka:
  1301. 00402014: 79 67 E8 77 6C 7D E8 77
  1302.  
  1303. Kernel32.Sleep:
  1304. 77E86779: E95FA95788 jmp 0004010DDh
  1305.  
  1306. new_sleep:
  1307. 004010DD: 8B442404 mov eax,dword ptr [esp+4]
  1308. 004010E1: 03C0 add eax,eax
  1309. 004010E3: 50 push eax
  1310. 004010E4: B827304000 mov eax,000403027h
  1311. 004010E9: FFD0 call eax
  1312.  
  1313. old_sleep:
  1314. 00403027: 6A00 push 0
  1315. 00403029: FF742408 push dword ptr [esp+8]
  1316. 0040302D: 90 nop
  1317. 0040302E: 90 nop
  1318. 0040302F: 90 nop
  1319. 00403030: 90 nop
  1320. 00403031: 90 nop
  1321. 00403032: 90 nop
  1322. 00403033: 90 nop
  1323. 00403034: 90 nop
  1324. 00403035: 90 nop
  1325. 00403036: 90 nop
  1326. 00403037: E94337A877 jmp Kernel32.77E8677F
  1327.  
  1328. ;this instruction is placed 1 byte after first instruction at Kernel32.Sleep
  1329. (77E86779)
  1330.  
  1331. Kernel32.77E8677F:
  1332. 77E8677F: E803000000 call Kernel32.SleepEx
  1333. ... ;following is unimportant
  1334.  
  1335. To make this clearer, this is how the original version of Kernel32.Sleep looks:
  1336.  
  1337. Kernel32.Sleep:
  1338. 77E86779: 6A00 push 0
  1339. 77E8677B: FF742408 push dword ptr [esp+8]
  1340. 77E8677F: E803000000 call Kernel32.SleepEx
  1341. 77E86784: C20400 ret 00004h
  1342.  
  1343.  
  1344. As you can see we copied first and second instruction (it was 6 bytes
  1345. here) and the relative jump pointed on the next instruction and that is how
  1346. it should be. We have to supposed here that relative jumps are not placed
  1347. as the first bytes of functions. If there would be we've got a problem. Next
  1348. problem is with APIs like ntdll.DbgBreakPoint. These are too short for this
  1349. method of hooking. And forasmuch as it is called by Kernel32.DebugBreak, it is
  1350. not hookable by changing IAT. But who want to hook function which does only
  1351. the int 3 call? But nothing is impossible. You can think about it and you can
  1352. find how to solve this. As I was thinking about this you can hook the following
  1353. function after this one (it would be damaged by rewritng first 5 bytes of the
  1354. previous function). Function DbgBreakPoint is 2 bytes long, so we can set some
  1355. flags here and try to write conditional jump on the begining of the second
  1356. function ... But this is not our problem now.
  1357. With the problem of saving original function relates then unhooking.
  1358. Unhooking is changing replaces bytes back to the original state. When rewriting
  1359. IAT you will have to return original address to the table if you want to do
  1360. unhooking. When using the five byte patch you will have to copy first original
  1361. instructions back. Both ways are realy simple and no need to write more about
  1362. this.
  1363.  
  1364.  
  1365. =====[ 3.2.4 Other process hooking ]============================================
  1366.  
  1367. Now we will do something practical with hooking during running. Who
  1368. want to deal with hooking own process? That is good only for learning basics
  1369. but it is not much practical.
  1370. I'll show you three methods of other process hooking. Two of them use
  1371. API CreateRemoteThread which is only in Windows with NT technology. The problem
  1372. of hooking is not so interesing for older windows version for me. After all
  1373. I will try to explain third method which I didn't practise, so it could be
  1374. unfunctional.
  1375. At first few about CreateRemoteThread. As the help says this function
  1376. creates new thread in any process and runs its code.
  1377.  
  1378. HANDLE CreateRemoteThread(
  1379. HANDLE hProcess,
  1380. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  1381. DWORD dwStackSize,
  1382. LPTHREAD_START_ROUTINE lpStartAddress,
  1383. LPVOID lpParameter,
  1384. DWORD dwCreationFlags,
  1385. LPDWORD lpThreadId
  1386. );
  1387.  
  1388. The handle hProcess can be get by OpenProcess. Here we have to have
  1389. necessary rights. The pointer lpStartAddress points on memory place in TARGET
  1390. process where the first instruction for new thread is. Because new thread is
  1391. created in target process it is in memory of target process. The pointer
  1392. lpParameter points on argument which will be refered to the new thread.
  1393.  
  1394.  
  1395. =====[ 3.2.4.1 DLL Injection ]==================================================
  1396.  
  1397. We are able to run new thread from any place in target process memory.
  1398. This is useless unless we have own code in it. The first method cheats on this.
  1399. It uses GetProcAddress to get actual address for LoadLibrary. Then routes
  1400. lpStartAddress to the address of LoadLibrary. Function LoadLibary has only one
  1401. parameter like the function for new thread in target process.
  1402.  
  1403. HINSTANCE LoadLibrary(
  1404. LPCTSTR lpLibFileName
  1405. );
  1406.  
  1407. We will use this similarity and we will refer the name of our DLL
  1408. library as lpParameter. After running new thread lpParameter will be on a place
  1409. of lpLibFileName. The most important thing here is behavior decribed above.
  1410. After loading new module into target process memory the initialization part is
  1411. executed. If we place specific functions which will hook functions we want to
  1412. we will win this stuff. After execution of initialization part, the thread will
  1413. have nothing to do and close but our module is still in memory. This method is
  1414. realy nice and easy to implement. This is called DLL Injection. But if you are
  1415. like I am, you don't like must of having DLL library. But if one doesn't care
  1416. about having this library it is the easiest and the fastest method (from the
  1417. programmers sight).
  1418.  
  1419.  
  1420. =====[ 3.2.4.2 Independent code ]===============================================
  1421.  
  1422. Going on the way of independent code is very difficult but also very
  1423. impressive thing. Independent code is the code without any statical addresses.
  1424. Everything is relative in it towards some specific place in itself. This code
  1425. is mostly done if we don't know the address where this code will be executed.
  1426. Sure, it is possible to get this address and then to relink our code so as it
  1427. will behave on the new address without errors but this is even harder than
  1428. coding independent code. Example of this kind of code can be the virus code.
  1429. The virus which infects executables in the way it adds itself somewhere into
  1430. this executable. In different executables will be the virus code on different
  1431. places depended e.g. on file structure on length.
  1432. At first we have to insert our code into target process. Then function
  1433. CreateRemoteThread will take care of running our code. So, at first we have to
  1434. get some information about target process and get handle with OpenProcess.
  1435. Then VirtualAllocEx will alloc some space in remote process memory for our
  1436. code. Finally we will use WriteProcessMemory to write our code on allocated
  1437. memory and run it. In CreateRemoteThread lpStartAddress will refer to allocated
  1438. memory and lpParameter can be whatever we want. Because I realy don't like any
  1439. unnecesarry files I use this method.
  1440.  
  1441.  
  1442. =====[ 3.2.4.3 Raw change ]=====================================================
  1443.  
  1444. There is not CreateRemoteThread in older windows version (without NT).
  1445. So we can't use this for hooking. There are probably other and better methods
  1446. how to hook than the method I will talk about now. In fact I don't know if this
  1447. will work in practice (one never know when use Windows) but theoretically is
  1448. everything ok.
  1449. We don't need to have our code in target process to hook its functions
  1450. at all. We have function WriteProcessMemory (this should be in all Windows
  1451. version) and we have OpenProcess, too. Last thing we need is VirtualProtectEx
  1452. which can change access to memory pages in target process. I can't see any
  1453. reason why not to hook target process functions directly from our process...
  1454.  
  1455.  
  1456. =====[ 4. Ending ]==============================================================
  1457.  
  1458. This small document ends. I will greet any extension which will
  1459. describe unmentionde methods of hook, I am sure there are a lot of them. I will
  1460. also greet any extensions in the parts which were not described so intimately.
  1461. You can also send me some source codes if they are fecund for the problem of
  1462. hooking e.g. for parts where I was lazy to write the code. The goal of this
  1463. document is to show deatails of every technics of hooking. I hope I've done
  1464. the part of this.
  1465. Special thanks to Z0MBiE for his work, so I haven't to code it myself
  1466. and spend ages by studying tables for getting instruction length.
  1467.  
  1468. ===================================[ End ]======================================
Advertisement
Add Comment
Please, Sign In to add comment