阅读:773回复:0
扩展SoftICE--6
Chapter 6: Moving to ring 3
--------------------------- Part of the Protected Mode Debug API is available also on ring3.In fact , some functions from WIN32 API like OutputDebugString relays on INT 41h to carry out the job. This opens more interesting possibilities , since you can write ring3 programs that interacts with a system debugger , retrieving info from it and instructing it to carry out various actions. Note that not entire API is disponible on ring3.Generally, experimenting won\'t harm as long as you are sure that a system debugger is installed. Chapter 7: How Numega\'s Loader works? ------------------------------------- Although this chapter is not directly related to extending system debuggers under Windows95 ive decided to present it inside this document because it treats a very important problem: Talking to VxD\'s from ring3.The basic problem is the question: How can I call the code from a VxD and how do I retrieve data from it?Well , there are more than one method to to this, but I will present only one.This method uses the DEVICE_IO_CONTROL mechanism to talk to a VxD.It also provides a very convenient way to manipulate complex data structures between ring3 and ring0.The only downside is that a certain architecture is imposed to the VxD which will be called using this method.The device driver is required to process the W32_DeviceIoControl message and to use a table of offsets to dispatch control to desired procedures. NuMega\'s loader uses this method to instruct SoftIce VxD to perform various actions. The mechanism is implemented within nmtrans.dll. The executable is a simple shell for an easy user interaction.Now let\'s see the API used to communicate in this way with a VxD and then let\'s look how NuMega\'s loader use them.Three WIN32 API functions are used: CreateFile , CloseHandle and DeviceIoControl. I\'m sure that all of you know very well CreateFile & CloseHandle so let\'s see DeviceIoControl. The DeviceIoControl function sends a control code directly to a specified device driver, causing the device to perform the specified operation. BOOL DeviceIoControl( HANDLE hDevice, // handle of the device DWORD dwIoControlCode, // control code of operation to perform LPVOID lpvInBuffer, // address of buffer for input data DWORD cbInBuffer, // size of input buffer LPVOID lpvOutBuffer, // address of output buffer DWORD cbOutBuffer, // size of output buffer LPDWORD lpcbBytesReturned, // address of actual bytes of output LPOVERLAPPED lpoOverlapped // address of overlapped structure ); DIOCParams STRUC Internal1 DD ? VMHandle DD ? Internal2 DD ? dwIoControlCode DD ? lpvInBuffer DD ? cbInBuffer DD ? lpvOutBuffer DD ? cbOutBuffer DD ? lpcbBytesReturned DD ? lpoOverlapped DD ? hDevice DD ? tagProcess DD ? DIOCParams ENDS Hope the structure is self-explanatory , tired of typing.Anyway it is used to pass and retrieve data to the called VxD service,as well as passing desired code of operation. How Numega use this functions? First CreateFile is called with LPCSTR lpszName parameter set to \" \\\\\\\\.\\\\SICE\".If Softice VxD is loaded this call will return a handle to the virtual device driver.After that DeviceIoControl is called with HANDLE hDevice set to the value returned by previously called CreateFile and DWORD dwIoControlCode set to a integer value which unique identifies what routine we want to be called from VxD.If the function succeeds the return value is TRUE. \"\\\\\\\\.\\\\SICE\" passed to CreateFile is the name of the virtual device we want to open.You can figure out very easy this name , IDA gives it to you for any VxD. When DeviceIoControl is called the system wraps to called VxD routine through a standard Windows95 VxD called vwin32.vxd.A DEVICE_IO_CONTROL message is broadcasted to the target VxD.In this moment esi register points to a DIOCParams type structure.The VxD code is responsible to annalize the requested service code ( DWORD dwIoControlCode) and see if it\'s a valid one. If it\'s valid , control is passed to the service routine witch must return with carry flag cleared to indicate success. If the service code does not exist, or an error occurs (insufficient nr. of parameters ...and so on ) we must return with carry flag set to indicate an error.Finally , Close Handle is called to destroy the handle. Let\'s annalize , for example , how the command history is saved to a file (the first listing is from nmtrans.dll , the second from winice.exe ver 3.22). A simple quick view in nmtrans.dll shows some interesting names.Two of them are interesting in our problem. They are DevIO_ConnectToSoftIce and DevIO_CopyLogInfo.Very suggestive names, isn\'t it?When we want to save log info control is passed to DevIO_CopyLogInfo. ...............................!!!!SEVERAL LINES STRIPED OUT!!!................................ disasembly listing of nmtrans.dll DevIO_CopyLogInfo ------------------- 10019999 call DevIO_ConnectToSoftICE // In fact this calls CreateFile // to open a handle to VxD 1001999E mov [ebp+var_1C], eax 100199A1 cmp eax, 0FFFFFFFFh // If we don\'t have a valid handle 100199A4 jz short loc_100199EA // jump out of here 100199A6 push 0 100199A8 lea eax, [ebp+var_24] 100199AB push eax 100199AC push 1Ch 100199AE lea eax, [ebp+var_40] 100199B1 push eax 100199B2 push 0 100199B4 push 0 100199B6 push 9C406018h //Push control code of operation //Remember this , it is a critical //value.It decides what service // will eventualy execute winice. // See below! 100199BB mov eax, [ebp+var_1C] 100199BE push eax //Push the handle to winice VxD on stack 100199BF call ds:DeviceIoControl //Call DeviceIoControl //At this point control will be passed to //Soft-Ice VxD. //Remember that the OS have to execute // several auxiliary operations , you // will not land directly in Winice! 100199C5 mov [ebp+var_20], eax 100199C8 lea esi, [ebp+var_40] 100199CB mov edi, ebx 100199CD mov ecx, 7 100199D2 repe movsd 100199D4 jmp short loc_100199EA So we learned that the dll\'s call into SoftIce VxD through DeviceIoControl Win32 API function.To figure out exactly what service will be called from target VxD we have to remember several things about VxD architecture.First of all we must know that every VxD have a ControlDispatch routine that receives mesages broadcasted by system.This control block identifies the messages and call coresponding routines.When this proc. is entered eax contain message code. Ida Pro 3.7 identifies very well this procedure,giving us a very good starting point. 00000096 Control_0 proc near ; DATA XREF: LCOD:0000055Ao 00000096 ; LCOD:0000407Co 00000096 call sub_7C8BB 0000009B cmp eax, 0 // case SYS_CRITICAL_INIT 0000009E jz loc_93E 000000A4 cmp eax, 1 // case DEVICE_INIT 000000A7 jz short loc_D8 000000A9 cmp eax, 2 // case INIT_COMPLETE 000000AC jz loc_BDC 000000B2 cmp eax, 6 // case SYS_CRITICAL_EXIT 000000B5 000000B5 loc_B5: ; DATA XREF: LCOD:000B4640o 000000B5 jz loc_BDE 000000BB cmp eax, 23h ; \'#\' // case W32_DEVICEIOCONTROL // // Using DeviceIoControl for talking // to VxD requires that this message // is processed! 000000BE jz loc_5FD // than jump to this location 000000C4 cmp eax, 0Fh // case SET_DEVICE_FOCUS 000000C7 jz loc_15F 000000CD cmp eax, 0Ch // case DESTROY_VM 000000D0 jz loc_19B 000000D6 clc 000000D7 retn The control is passed to the handler for W32_DeviceIocontrol message (loc_5FD in this case). 000005FD loc_5FD: ; CODE XREF: Control_0+28 000005FD push ebx // 000005FE push esi //Save those registers 000005FF push edi // 00000600 push 10h // EnterMutex param2 00000602 push ds:dword_40BF // EnterMutex param1 00000608 VMMcall _EnterMutex // Create a mutex to ensure that only // one thread will acces this code at // a given time 0000060E add esp, 8 // restore stack as at 5ff 00000611 push esi // save esi 00000612 mov esi, offset dword_40C3 // pointer to an Exception_Handler_Struc // in this struct are defined the // type of handler and memory range // what is guarded 00000617 VMMcall Install_Exception_Handler // install a ring0 exception handler // if something goes wrong we can // trap the problem 0000061D pop esi // restore the esi // esi contain a pointer to a DIOCparams // struct (All info you pass to ring3 // DeviceIOControl + some not very // important things for us 0000061E call sub_4B4F5 // ??? unexplored by me 00000623 mov ds:dword_40B7, 1 0000062D push 1 0000062F call sub_8595C // ??? unexplored by me 00000634 push eax 00000635 mov ds:dword_40BB, esp 0000063B mov dword ptr [esi+20h], 0 // set number of bytes returned // may be modified by the requested // service 00000642 mov ecx, [esi+0Ch] //load in eax dwIoControlCode //from DIOCParams.dwIoControlCode 00000645 mov edx, ecx 00000647 shr edx, 10h 0000064A cmp edx, 9C40h // check for validity and reduction 00000650 jnz short loc_672 00000652 mov edx, ecx 00000654 shr edx, 2 00000657 and edx, 0FFFh 0000065D cmp edx, 800h 00000663 jl loc_8BD 00000669 sub edx, 800h 0000066F inc edx 00000670 mov ecx, edx // end check for validity and reduction // load basic service code in ecx // maximum value for a valid request // will be 0xB 00000672 00000672 loc_672: ; CODE XREF: LCOD:00000650 00000672 inc ecx // services are 0 based so increment 00000673 cmp ecx, 0Ch // is service available? 00000679 jnb loc_8BD // if no , Get Out of here! 0000067F jmp ds:off_7584[ecx*4] //else jump to the requested routine // it\'s address is stored in a DWORD // array begining in this case at // off_7584 // The mutex object is removed elsewhere in the code as well as the exception handler // Not listed here because it\'s unimportant for our problem Remember the control code of operation passed to DeviceIoControl?.This is the moment then it becomes crucial.As already told , at this moment the ESI register points to a DIOCParams type structure.This structure contains all info passed to DeviceIoControl. Now if you watch the code above you will notice that from 0x635 to 0x672 a reduction of this value to a much smaller one is performed.In fact , the maximum value contained in ecx at this step is OxB , which BTW is the number of services that SoftIce expose through this interface. ( in fact , the maximum number of services is 0xC ,but this contains the default DIOC_GETVERSION service). At location 673 the code looks if this service is in range (in SICE are implemented 0x0c services what can be called using this method).If it determines that it\'s a valid service , the code jumps to the start adress of requested service. This adress is stored in a table , in our case at ds:off_7584. 00007584 off_7584 dd offset off_686 // if ecx = 0 00007588 dd offset off_68B // if ecx = 1 0000758C dd offset loc_690 // if ecx = 2 00007590 dd offset loc_6E8 // if ecx = 3 00007594 dd offset loc_71C // if ecx = 4 00007598 dd offset loc_7F6 // if ecx = 5 0000759C dd offset loc_825 // if ecx = 6 000075A0 dd offset loc_75C // if ecx = 7 000075A4 dd offset loc_78B // if ecx = 8 000075A8 dd offset loc_7BA // if ecx = 9 000075AC dd offset loc_8B6 // if ecx = A 000075B0 dd offset loc_85D // if ecx = B ECX == 0 coresponds to a default DIOC_GETVERSION service .All others values between 0x1 and 0xb at VxD services called by one of the folowing functions: DevIO_ConnectToSoftICE (00019490) DevIO_CopyLogInfo (00019940) DevIO_LoadExports (00019760) DevIO_LoadNm32SymbolTable (00019630) DevIO_Nm32QueryTableInfoFirst (00019C50) DevIO_Nm32QueryTableInfoNext (00019D60) DevIO_Nm32QueryTables (00019B40) DevIO_Nm32RemoveSymbolTable (00019E40) DevIO_Nm32TranslateError (000194F0) DevIO_Nm32VersionInfo (00019840) DevIO_SetWLDRBreak (00019A30) All this functions exported by nmtrans.dll use the same mechanism.Of course , operation codes ar different , as well as the data passed and retrieved. Looking at this table we have a clear picture of the starting adress of the VxD routines what are called from ring3.Pretty interesting , isn\'t it? And we can call them any time now , once we figured what code of operation coresponds to it. Note : al C++ style comments in the listing there are NOT auto generated by IDA. |
|
最新喜欢:![]() |