Hi Guys,
I am hoping one of you guru's can point me in the right direction.
I am writing a test app at the moment which uses CreatePipe followed by CreateProcess to load a system executable called DiskPart.exe.
In the debugger (OllyDbg) i can issue commands to DiskPart and read back the responce using the WriteFile and ReadFile functions without any problem.
However, during normal use, this does not work and I presume it's because the code is executing to quickly, by this I mean that the time difference between me issuing a command and then reading back the responce does not give DiskPart enough time to complete the task i instructed it to carry out.
Therefore, I am after a solution where I can only read back the responce when DiskPart has finished the task.
Ideally I don't want to put set wait times in the code as this could become problematic on other computers.
Thanks for taking the time to read this, Colin.
you can probably use GetExitCodeProcess to get the return code
you have to create the process with PROCESS_QUERY_INFORMATION access right
you will also need the process handle, which is in the PROCESS_INFORMATION structure
if the return code is STILL_ACTIVE, use Sleep to wait some time period (something in the 10 to 50 mS range should work)
then, get the code again
a problem with this is that if STILL_ACTIVE (103h) is returned as a valid return code, you won't know it has terminated :P
most processes, especially those written by MS, avoid returning that value
another way to go is to use ShellExecute - i think you could make that work, but it's more difficult
Quote from: colinr on September 04, 2011, 06:33:04 PMIn the debugger (OllyDbg) i can [...] during normal use, this does not work
maybe a rights problem - try to start your program as administrator.
@qword, it's definitely because I'm single stepping the code, the spawned application gets to finish it's task with loads of time to spare!
@dedndave, thanks for that info, I'll try it later on this evening, time permitting. Just one more point, I don't know how familiar you are with DiskPart, but it seems to run in its own shell, instead of having C:\> as the prompt, it is DISKPART>.
To exit back to the DOS prompt you have to type quit.
Now here might be the next problem, I intend to pipe multiple commands to diskpart one at a time and obviously retrieve each responce as they happen, would the GetExitCodeProcess still work in this instance as diskpart does not actually terminate, it just becomes idle, resting at the DISKPART> prompt between commands. It would not be practical to exit diskpart after each command as it takes about 3-4 seconds to enumerate the disks when it is executed.
I did try to interface with the Virtual Disk Service about a year ago without luck as it heavily relies on COM, and not knowing any C whatsoever, it was a non runner for me.
Diskpart drives the VDS and i think it's the easiest (not necessarily the best) way of interacting with the VDS for me.
Thanks to both of you, Colin.
well - you have to pipe, perhaps, several commands before something happens :P
i would try to arrange the code so that you exit after each operation that reads or writes the disk
write a "wrapper" routine so you can pump commands through, waiting for DiskPart to exit and returning a result code
the program will not execute the exit command until the operation has completed
i forget the details of how to use DiskPart
if you can execute several commands through the command line, you may be able to do away with piping
you could also create a script file and do it that way
if you want to use the pipe approach, you can see when a command has finished by apperance of the prompt
for DiskPart, i think that's a hyphen "-"
Quote from: colinr on September 04, 2011, 08:20:09 PM
@qword, it's definitely because I'm single stepping the code, the spawned application gets to finish it's task with loads of time to spare!
ReadFile normally blocks until the specified number of bytes has been read or a handle with write access to the pipe/file has been closed (AFAIK) ...
from the documentation....
QuoteWhen using the DiskPart command as a part of a script, it is recommended that you complete all of the
DiskPart operations together as part of a single DiskPart script. You can run consecutive DiskPart scripts,
but you must allow at least 15 seconds between each script for a complete shutdown of the previous
execution before running the DiskPart command again in successive scripts. Otherwise, the successive
scripts might fail. You can add a pause between consecutive DiskPart scripts by adding the timeout /t 15
command to your batch file along with your DiskPart scripts.
http://technet.microsoft.com/en-us/library/cc766465%28WS.10%29.aspx
15 seconds seems like an awfully long time :P
can you be more specific as to what you are trying to do ?
are you creating partitions ?
i would probably use MbrWizard - the older commandline version
it has one small bug
certain values need to be specified in hex, followed by 'h'
http://mbrwizard.com/
click the "Downloads" tab - then the "Legacy" tab
version 2.0b is available for 32 and 64-bit OS's
@dendave
It's actually a small GUI for a forensic application, well actually Windows 7 PE.
The app will be used to set disks to read-only/read-write and assign drive/unassign drive letters to volumes.
Not too intense but initially, the app will set all disks to read-only to prevent any writes, then the user will use the GUI to enable read/write and/or assign drive letters to disks of their choice.
It does work at the moment, a friend of mine who is more than capable at C programming wrote a DLL for me to access the VDS to carry out all of the above actions with the exception of assigning drive letters to disks, however, due to work commitments, he is unable to finish the project, therefore, I've decided to write new code to pipe commands to diskpart then parse the resulting text returned to then display to the end user in a GUI.
Hope this explains what I'm after, Colin.
that being the case, MBRWizard should work for you
not sure if it will change drive letters, though
i seem to recall something about drive letters in WMI
if you use the forum search tool, you may find some info on WMI
maybe these links will help...
http://msdn.microsoft.com/en-us/library/aa364014%28v=vs.85%29.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2011/03/14/change-drive-letters-and-labels-via-a-simple-powershell-command.aspx
Slightly off topic, but I do have another idea!
Using OllyDbg, i have found the precise location where DiskPart outputs to the screen, is there anyway that I can patch DiskPart at this location to jump into my code, the I can intercept the strings without using the read pipe, for instance, redirect Int x to point to my code or even directly jump?
It may not be possible on 8086 machines, due to protected memory, however, going back 20 years, it was perfectly possible to do on 68000 machines.
My idea would be to load DiskPart as an executable from my code, but do not execute it at that point, patch, then execute?
you can do that, although it probably wouldn't be considered "clean" :P
all you need is the handle to the console window
INVOKE GetConsoleWindow
mov hConsole,eax
hang on - lol
that won't work for what you want
you have to enumerate processes and find the one you want, then get the window handle for it
a lot of code, but do-able
not a great way to go, anyways :P
however, you can easily redirect console output to a text file and open and read that
So just to clarify, would I still set up the write pipe and load diskpart with create process?
then use getconsole window to find the memory address of the oep of diskpart?
How would one go about redirecting, lets say int3 then start diskpart from its loaded but not executing state?
you will have to excuse my lack of understanding on this, its about 20 years ago that I attempted anything like this!
Just seen your last post, text files again would be an issue as I would still have to implement forced waits to allow the text file to be written, I'll have a look at pre patching diskpart first rather than on the fly. This is not too much of an issue as one of the forensics guys at MS is in on this project anyway and there has been substatial patching to the vds anyway to maintain forensic soundness
here are a few questions.....
1) what is the minimum OS the program is required to run under
2) you want just these 2 functions ?
a) change drive letter
b) set/clear read-only attribute
3) do you intend to sell it ?
(if not, we can use all kinds of stuff)
changing a drive letter doesn't look that bad....
operation: function used
get and store the volume GUID path: GetVolumeNameForVolumeMountPoint
remove the drive letter: DeleteVolumeMountPoint
assign new drive letter to stored GUID path: SetVolumeMountPoint
Notes:
1) drive letter strings must be in the form "X:\",0
2) the GUID string can be up to 50 bytes long
3) good idea to make sure the target letter is not in use prior to beginning :P
@dedndave, There is no money in the project, it's a free tool for the forensics community, actually the home page is here: http://winfe.wordpress.com/
It just so happens that the DLL that i use at the moment has become redundant due to it not being finished, therefore, I have had to take this radical step at a late stage in the game to actually get something that can be released.
I've looked at the drive letter assignment stuff and it does work as I've tried it, however, the Virtual Disk Service does not return information that is useful, for instance, the disk/volume GUID's appear to be different and //./PhysicalDrive0 is not always the same as the disk that diskpart referrs to as disk 0.
I am going to have a look at modifying diskpart somehow to redirect to my code, whilst not the perfect way of doing things, it would be perfect for me, especially as it's running in a custom boot disk environment.
The only question I have is, how do I set one of the Int vectors to contain a pointer to my code?
Thanks again.
hi,
I've made a quick test with DiskPart.exe, which requires Administrator rights. If your application has not this rights, you can't redirect the output to your application - probably your debugger runs as adminstrator(?). The following application redirect the output to it's own console, if it runs as Admin:
include masm32rt.inc
.code
main proc
LOCAL sui:STARTUPINFO
LOCAL pi:PROCESS_INFORMATION
invoke RtlZeroMemory,ADDR sui,SIZEOF sui
mov sui.cb,SIZEOF sui
fn CreateProcess,"DiskPart.exe",0,0,0,0,0,0,"C:\Windows\System32",ADDR sui,ADDR pi
invoke WaitForSingleObject,pi.hProcess,-1
inkey
exit
main endp
end main
Thanks qWord.
I've actually kind of got that far, the problem arises when I come to read the responces via the pipe, without some sort of delay, i read back before diskpart has actually finished outputting its text.
I cant open a new instance of diskpart for each command that i wish to execute as it would just impose too much delay.
I intend to pass multiple commands, one at a time, and then readback the results of these commands all in a single session.
Colin,
That type of technology was viable in the real mode DOS days but is not even close to useful in a protected mode OS. Cross process access is difficult at best due to the threading and protection mechanisms built into the OS. Getting piped output is viable then displaying it in whatever way you like afterwards. You can point it at a console, write it to a GUI Window or a control in a GUI window.
Its a 2 part operation, get the data from the external running APP then display it in a convenient form.
Thanks Hutch,
Protected mode did cross my mind and I could see the problems you described.
So back to my original problem, when I issue a command to diskpart such as 'List Disk', it has not finished the operation before I attempt to read the outputted text back through the pipe (the buffer is still empty). What is the best way for me to detect that diskpart has completed the operation. The text returned is also dynamic, so that I will never know how many bytes are due to be returned.
Would PeekNamedPipe meet with my criteria with a few milliseconds delay between subsequent calls as the output will always end with 'DISKPART>'. If it would work, I dare say I would need to add some kind of additional delay just in case diskpart crashes and does not return anything, otherwise i will end up in a dreaded infinite loop!
I really do wish I could learn C++ as all the API's for the Virtual Disk Service are provided :'(
Colin.
i would try to get away from using DiskPart :U
dedndave,
I wish i could but it offers all of the VDS services that I require, i've never been able to find an IOCTL code to set a disk to read-only.
It's a case of either learning C++ in super quick time or write a kernel mode driver which just the thought of, scares me to death!!
I'll have another play with it when I get the time to apply myself to it.
Colin.
well - to set a disk to read-only requires modification of the MBR
truthfully, that is a little bit outside the scope of the forum guidelines :P
anyways - i don't think it can be done strictly with IOCTL
it is more of a COM task, transacted operations and all that stuff
or perhaps WMI - COM, again
MBRWizard lets you do all the stuff you need to do in command line switches
it also allows you to create and restore backup copies of the MBR
no need for the console-under-console stuff of DiskPart
another path might be PowerShell
attached is the 32-bit version
not sure how well it would work under win7 - i think they bumped the NTFS version to 6
here we go
this may be a better alternative, as it is provided and supported by MS
Sector Inspector...
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=19470
At last I appear to have it working, I will share my findings of how I did it by modifying a code snippit that i came across!
Please excuse the lack of error checking but it is only test code.
.386
.model flat,stdcall
option casemap:none
include C:\masm32\include\windows.inc
include C:\masm32\include\masm32.inc
include C:\masm32\include\kernel32.inc
include C:\masm32\include\user32.inc
include C:\masm32\include\advapi32.inc
includelib C:\masm32\lib\kernel32.lib
includelib C:\masm32\lib\masm32.lib
includelib C:\masm32\lib\user32.lib
includelib C:\masm32\lib\advapi32.lib
.data
AppToSpawn db "c:\windows\system32\diskpart.exe",0
ListDisk db "List Disk",0h
ExitDiskPart db "exit",0h
.data?
startinfo STARTUPINFO <>
secat SECURITY_ATTRIBUTES <>
secdes SECURITY_DESCRIPTOR <>
procinfo PROCESS_INFORMATION <>
newstdin DWORD ?
newstout DWORD ?
readout DWORD ?
writein DWORD ?
bytesRead DWORD ?
bytesWrit DWORD ?
avail DWORD ?
buffer db 1024 dup (?)
.code
start:
invoke InitializeSecurityDescriptor,addr secdes,SECURITY_DESCRIPTOR_REVISION
invoke SetSecurityDescriptorDacl,addr secdes,TRUE,NULL,FALSE
mov secat.lpSecurityDescriptor,offset secdes
mov secat.nLength,sizeof SECURITY_ATTRIBUTES
mov secat.bInheritHandle,TRUE
invoke CreatePipe,addr newstdin,addr writein,addr secat,0h ;Send Data
invoke CreatePipe,addr readout,addr newstout,addr secat,0h ;Receive Data
invoke GetStartupInfo,addr startinfo
mov startinfo.dwFlags,STARTF_USESTDHANDLES+STARTF_USESHOWWINDOW
mov startinfo.wShowWindow,SW_HIDE
mov eax,[newstout]
mov startinfo.hStdOutput,eax
mov startinfo.hStdError,eax
mov eax,[newstdin]
mov startinfo.hStdInput,eax
invoke CreateProcess,NULL,addr AppToSpawn,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,addr startinfo,addr procinfo
call ActivityDelayWithRead
jnz short FatalError
mov ecx, 10
invoke WriteFile,writein,addr ListDisk,ecx,addr bytesWrit,NULL
call ActivityDelayWithRead
jnz short FatalError
mov ecx, 5
invoke WriteFile,writein,addr ExitDiskPart,ecx,addr bytesWrit,NULL
FatalError:
invoke CloseHandle,newstdin
invoke CloseHandle,writein
invoke CloseHandle,readout
invoke CloseHandle,newstout
invoke ExitProcess,0h
ActivityDelayWithRead:
mov esi,100 ;5 seconds delay overall, 100*5ms
ActivityLoop:
invoke Sleep,50 ;50 miliseconds
invoke RtlZeroMemory,addr buffer, 1024
invoke PeekNamedPipe,readout,addr buffer,1023,offset bytesRead,addr avail,NULL
lea edi, buffer
mov ecx, 1024 ;Let's search for 1024 btes
mov al, ">" ;We are looking for the greater than symbol
cld ;Clear direction
repne scasb
je short FoundDiskPartPrompt
dec esi
jne short ActivityLoop
xor eax,eax
not eax
test eax, eax
ret
FoundDiskPartPrompt:
invoke ReadFile,readout,addr buffer,1023,addr bytesRead,NULL
xor eax, eax
test eax, eax
ret
end start
:U