hi all, i know well that you're tired to see my stupid help requests about mbr, thunks, QT_Thunks and so on. This will be my last and than i will let HD mbr reading for better times :( Ok, if you don't have better things to do, i try to explain the issue... The idea suggested by a friend was to read HD mbr under win95 using asm32. First, with some help, i've found a Micro$$$oft article that suggest to use DeviceIoControl function (normally used in NT), calling to VWIN32.VXD, that seems could simulate int13.
DeviceIoControl() is called using a handle to a VxD rather than a handle to a disk drive or disk partition. Obtain a handle to VWIN32.VXD by using CreateFile( "\\\\.\\VWIN32", ... ). Use this handle in calls to DeviceIoControl() to perform volume locking (Int 21h Function 440Dh, Subfunctions 4Ah and 4Bh), and then to perform BIOS calls (Int 13h), Absolute Disk Reads/Writes (Int 25h and 26h), or MS-DOS IOCTL functions (Int 21h Function 440Dh).But i've seen that this method don't work with HD, it work only for floppies :( So i've found another M$ article that says PRB: DeviceIoControl Int 13h Does Not Support Hard Disks (first seems is possible, now it's no more possible) So they suggest to code a 32 bit dll that call a 16bit dll that perform a call to DPMI service 31h that can simulate int13h with a C code example..... I've try also this way but it's too complicated for me now. I can't debug the errors trough the dll calling.... This method seems a big mess to realize. So this is the story. If someone can give me an idea for an easier way to read MBR i will be very very grateful. many thanks to all that has read this heavy message ( & sorry for bad english :( ).
Fdisk works under Windows so there must be a way to read the MBR using the Win32 api. Sorry i don't know how
fdisk is a dos app, and thus uses dos calls. Which are fine under win32. However, sure there must be a way to do it natively in win32, as programs such as partitionmagic (at least newer versions) and defrag can operate from within windows. It would, however, be very much like microsoft to not speak very loudly of how to do this...
You need to read CreateFile, that explains opening the logical partition, or phyisical device...
Also remember to CloseHandle again afterwards (and always look both ways before crossing the road :D ). Mirno
.data File1 db "\\.\C:", 0 ;Open Logical partition C: File2 db "\\.\PHYSICALDRIVE1",0 ;Open the second logical drive (start at 0) .code invoke ADDR File, GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, \ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ;You must use FILE_SHARE_WRITE when opening a logical drive!
Is it possible to make the same interrupts calls as the ones used by fdisk ?
thanks to have resurrected my message from the grave. I've always tought that apps like partitionmagic read MBR in easy way. But microsoft suggest to use a call to a 16bit code from where you can call DPMI service. That mean that you can use interrupts as in dos but staying in protected mode, as windows32 is. The key to switch to a 16 bit code seems to be undocumneted function QT_Thunk (in Kernel32.dll). This function permit to jump to 16 bit code that use logical addressing (SEG(16):OFF(16)). But it is a too difficult way for me. There must be a better way ....
Try to translate the C program into Assembly. You have to make two DLLs and a win32 executable. The first dll is a 16-bit dll. It defines a function that calls the DPMI interrupt to read the MBR. The second dll is a 32-bit dll. In this dll, you need to define a function that will call the function defined in the 16-bit dll. The last step is to make an executable that will call the function defined in the 32-bit dll. To summarize : 1. Write the source file for the 16-bit dll 2. Write the source file for the 32-bit dll 3. Write the thunk script of the msdn article 4. Use the thunk compiler (you can find it in the 98 ddk) to compile the thunk script. It will generate an asm file. 5. Compile the asm file twice (with -DIS_16 and -DIS_32) 6. Link the 16-bit thunk object code with the 16-bit dll object code -> you have the 16-bit dll 7. Link the 32-bit thunk object code with the 32-bit dll object code -> you have the 32-bit dll 8. Write the asm source file of your application 9. Link it with the 32-bit dll. It's interesting. The MASM manual explains how to build a 16-bit dll, so technically it is possible to code everything in asm.
I've tried to translate the program in the msdn article but I had problems with the 16-bit. I can't use the 32-bit rc compiler to set the dll version to 40. I've tried to modify the dll header but without success. The dll initialization function always failed. However, I've found 2 dlls in the windows\system directory (cvrt32.dll and cvrt16.dll) that exports the function ReadPhysicalSector_16 and ReadPhysicalSector_32, the same function as the ones described in the msdn article. Here is a program example that uses the dll to read the mbr :
It works but the cvrt16 and cvrt32 dll were probably made using a 16-bit C compiler. If someone knows how to make a 16-bit dll in asm, please explain it in the message board. Thanks !
.386 .model flat, stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc .DATA dll32 BYTE "Cvt32.dll", 0 funcName BYTE "_ReadPhysicalSector_32@12", 0 MsgError1 BYTE "Can't load dll", 0 MsgError2 BYTE "Can't load proc", 0 MsgError3 BYTE "ReadPhysicalSector failed", 0 align 4 buffer BYTE 512 DUP (0) .CODE start : INVOKE LoadLibrary, addr dll32 .IF ( eax ) INVOKE GetProcAddress, eax, addr funcName .IF ( eax ) ;// call the function in the dll push 512 ;// buffer size push byte ptr offset buffer ;// buffer address push 080h ;// hard drive 0 call eax .IF ( eax ) ;// ... ;// here you can use a debugger to see the content of the buffer ;// for example, you can see that the buffer ends with the mbr signature (55AA) ;// .... xor eax, eax .ELSE ;// error msg mov eax, offset MsgError3 .ENDIF .ELSE mov eax, offset MsgError2 .ENDIF .ELSE mov eax, offset MsgError1 .ENDIF .IF ( eax ) INVOKE MessageBox, NULL, eax, NULL, MB_OK .ENDIF INVOKE ExitProcess, NULL END start
karim, i was trying the 16 bit dll. The dll is transated from M$ C example. I think there could be some error but i can't debug:
locals jumps model small, windows pascal .386p extrn GlobalDosAlloc :FAR extrn GlobalDosFree :FAR extrn UnlockSegment :FAR extrn LocalInit :FAR ; The MAKEWORD macro creates an unsigned 16-bit integer by concatenating two given unsigned character values. mkw MACRO lowerbyte, higherbyte xor eax,eax xor ebx,ebx mov bl,higherbyte shl bx,8 mov al,lowerbyte or ax,bx ENDM ; The MAKELONG (mkl) macro creates an unsigned 32-bit value by concatenating two given 16-bit values. mkl MACRO loworder, hiorder xor eax,eax mov ebx,hiorder shl ebx,16 mov eax,loworder or eax,ebx ENDM ; The HIWORD (hwd) macro retrieves the high-order word from the given 32-bit value. hwd MACRO bigword ;; Retrieves the high word from double word argument mov eax,bigword shr eax,16 ;; Shift 16 for high word to set to high word ENDM ; The LOWORD (lwd) macro retrieves the low-order word from the given 32-bit value. lwd MACRO bigword ;; Retrieves the low word from double word argument mov eax,bigword and eax,0FFFFh ;; Set to low word ENDM tagRMCS STRUC reg_edi dd ? reg_esi dd ? reg_ebp dd ? reg_ebx dd ? reg_edx dd ? reg_ecx dd ? reg_eax dd ? wFlags dw ? reg_es dw ? reg_ds dw ? reg_fs dw ? reg_gs dw ? reg_ip dw ? reg_cs dw ? reg_sp dw ? reg_ss dw ? tagRMCS ENDS .const SECTOR_SIZE equ 512 ; // Size, in bytes, of a disk sector CARRY_FLAG equ 0001h TRUE equ 01h NULL equ 00h FALSE equ 00h .data hInstance dw ? Address32 dd ? CodeS dd ? callStruct tagRMCS > .code LibEntry proc hinst:word, hdataseg:word, heapsize:word, cmdline:dword mov eax, TRUE ret LibEntry endp ;/*-------------------------------------------------------------------- ; ReadPhysicalSector1() ; ; Calls DPMI to call the BIOS Int 13h Read Track function to read the ; first physical sector of a physical drive. This function is used to ; read partition tables, for example. ; ; Parameters ; bDrive ; The Int 13h device unit, ; 0x00 for floppy drive 0 ; 0x00 for floppy drive 1 ; 0x80 for physical hard disk 0 ; 0x81 for physical hard disk 1 ; etc. ; ; lpBuffer ; Pointer to a buffer that receives the sector data. The buffer ; must be at least SECTOR_SIZE bytes long. ; ; cbBuffSize ; Actual size of lpBuffer. ; ; Return Value ; Returns TRUE if the first sector was read into the buffer pointed ; to by lpBuffer, or FALSE otherwise. ; ; Assumptions ; Assumes that sectors are at least SECTOR_SIZE bytes long. ;--------------------------------------------------------------------*/ ReadPhysicalSector1 Proc bDrive:BYTE, lpBuffer:DWORD, cbBuffSize:DWORD LOCAL fResult :DWORD, callStructOff :DWORD, gdaBuffer :DWORD, RMlpBuffer :DWORD, PMlpBuffer :DWORD
Yes, I'm interested. When you translate the exemple from the MSDN, remember that it is splitted into 3 parts : a 16-bit, a 32-bit dll and win32 executable. The 32-bit dll and win32 exe are easy to make. The problem is the 16-bit dll. According to MASM manual, a 16-bit dll must export a WEP procedure and an entry point. Functions in the dll must use a special prolog and epilog. The MSDN says that the dll's version number must be marked to 40. I can make the 16-bit dll but I can't mark it 40. When I link the 32-bit dll implicitely, the win32 program crashes. When I load the dll explicitly with LoadLibrary, the function failed and I must restart the computer if I want overwrite the 16-bit dll file. I don't know how to solve the problem. In the windows\system directory, there are a lot of 32-bit dll that calls 16-bit dll. It must be possible to make the same thing in asm.
karim, what i'm trying to do is DO NOT use 32bit dll passage. This to reduce the operation in 2 steps (more easy). From this article it seems possible use QT_Thunk to jump directly to 16bit dll withou creating a 32 bit one :) I've already created the 32bit app that should call the 16bit dll and it works ! But then a have an error in the 16bit dll and i cant debug :( Now i'mlocked here :( On my application the steps to call 16 bit dll are (don't look @ error handling):
And the call works. if you prefer i can send my entire app. by email.
@st1: call LoadLibrary16, offset DiskPartyDll16 ; loading my 16bit library cmp eax,32 jg @st2 mov Error,1 ; error handling mov eax,4 jmp ErrorHandling @st2: mov hInst16,eax call FreeLibrary16, hInst16 ; free library cmp eax,0 jg @st3 mov Error,1 ; error handling mov eax,5 jmp ErrorHandling @st3: call GetProcAddress16, hInst16, offset RPS1 ; loading 16 bit address !! cmp eax,0 jg @st4 mov Error,1 ; error handling mov eax,6 jmp ErrorHandling @st4: mov eax, offset MBRbuffer mov MbrAddress,eax push 80h ; drive push MbrAddress ; offset MBRBUFFER push 512 ; size of buffer/MBR mov edx,eax ; 16:16 bit address call QT_Thunk
oops, becouse now i'm in my lunch time @job, i've added some lines that was missing without trying to compile. Sorry, I've overwrote eax, where is stored the address to call. Please replace @st4 code with these using edi ...
@st4: mov edi, offset MBRbuffer mov MbrAddress,edi push 80h ; drive push MbrAddress ; offset MBRBUFFER push 512 ; size of buffer/MBR mov edx,eax ; 16:16 bit address call QT_Thunk
As the article said, you can't pass 32-bit pointers directly. You have to use the thunk mechanism to convert 32-bit pointers to 16:16 pointers that can be used in 16-bit code. This may be the reason why your program doesn't work.
karim, i've seen that i'm going on the problem as a monkey. I can't get out if i translate examples from C or if I copy them from other asm examples without understant how real-mode and proteced mode works. 1) Think it's better i understand well some points as logical addressing (16:16), 32to16bit stack pointer change ... and all other points involved on this mess. 2) Now I've installed softICE. Before i was using OllyDBG, good 32bit debugger but it couldn't debug 16bit code. SoftICE is very good becouse let me watch inside 16bit dll. I've soon seen that the error of my 16bit dll is in a 'POP ES' instruction. Probably i can't pop a 16bit value becouse stack is 32bit. But, how i've said, i've to study, to understand a lot. Thanks for your interests and helps. When i will have learned all these mysterious points I will come back out on the forum with a new topic (hope with the working code to read MBR) but i think the way is hard. Thanks for all (i apologize for my bad english, hope you have understood the meaning of the message). Angelo
It seems like a lot of work just to read sector 1 on track 0 head 0 -- but this time M$ has an excuse: all disk i/o goes through ROM BIOS, even now, and that code is (as far as I know) still in 16-bit mode. PS (edit): on my Win95 jalopy, DEFRAG.EXE and several important .cpl files are 16-bit NE's, not PE's. Could someone see if this is true on NT too? This message was edited by Larry Hammick, on 5/28/2001 8:30:26 PM
Hm. I thought that win9x had it's own 32bit code handling the harddrives directly? I know that a hell of a lot of stuff thunks down to 16bit protected mode (like, the GDI stuff). And a few things might thunk down to 16bit realmode (bios stuff). But unless you system is in "compatibility mode" because of some flaky old driver, harddrive access should be 32bit. HM. Looks like defrag.exe is also NE on windows 98. Perhaps it's just plain easier getting this form of access from 16bit protected mode? As for the "simulaterealmodeint" approach, that's plain disgusting :). I think there's a way to do it with DeviceIoCTL's to the correct VXD, but... *blank*
Well, f0dder, I might be all wet about bios for HD; I am somewhat out of my depth here. But look at eisa.vxd -- it is too small to do much, and maybe it just translates 32-bit calls into 16-bit or bios calls. Anyway, if someone succeeds in reading an absolute sector, please let me know. DOS was so much simpler...