Extract deleted file from NTFS using PowerShell (Preparation)


Here is main part

I implemented PowerShell script that extract file record from NTFS drive.
I coded in PowerShell for following reaseons.
  • It is available on standard Windows envirnment.
  • It is easy to modify after distribution because it is script.
  • Win32 API functions are available.

Folloing 4 Win32 APIs were userd to extract file record.
  • CreateFile
  • SetFilePointerEx
  • ReadFile
  • CloseHandle
CreateFile is used to open disk drive as file. SetFilePointerEx and ReadFile are used for retrieving record from specified accesspoint on disk drive. CloseHande is userd to close file handle. These functions are available on kernel32.dll

First I coded a script kernel32.ps to create object to call these Win32 APIs. By creating dinamic module, dynamic types and dynamic methods as assembly, functions on kernel32.dll are invoked via the assembly.

kernel32.ps1
#Win32API Class
$domain = [AppDomain]::CurrentDomain
$dynassembly = new-object system.reflection.assemblyname("DynamicAssembly")
$assemblybuilder = $domain.defineDynamicAssembly(
    $dynassembly,
    [system.reflection.emit.assemblybuilderaccess]::run
)
$modulebuilder = $assemblybuilder.definedynamicmodule("DynamicModule", $false)
$typebuilder = $modulebuilder.definetype("kernel32", "Public, Class")

#CreateFile
$createfilemethod = $typebuilder.definemethod(
    "CreateFile",
    [system.reflection.methodattributes] "Public, Static",
    [IntPtr],
    [Type[]] @(
        [string],
        [uint32],
        [uint32],
        [IntPtr],
        [uint32],
        [uint32],
        [IntPtr]
    )
)
$createfiledllimport = [system.runtime.interopservices.dllimportattribute].getconstructor(@([string]))
$createfilefieldarray = [system.reflection.fieldinfo[]] @(
     [system.runtime.interopservices.dllimportattribute].getfield("EntryPoint"),
     [system.runtime.interopservices.dllimportattribute].getfield("PreserveSig"),
     [system.runtime.interopservices.dllimportattribute].getfield("SetLastError"),
     [system.runtime.interopservices.dllimportattribute].getfield("CallingConvention"),
     [system.runtime.interopservices.dllimportattribute].getfield("CharSet")
)
$createfilefieldvaluearray = [object[]] @(
     "CreateFile",
     $true,
     $true,
     [system.runtime.interopservices.callingconvention]::winapi,
     [system.runtime.interopservices.charSet]::auto
)
$createfilecustomattribute = new-object system.reflection.emit.customattributebuilder(
     $createfiledllImport,
     @("kernel32.dll"),
     $createfilefieldarray,
     $createfilefieldvaluearray
)
$createfilemethod.setcustomattribute($createfilecustomattribute)

#SetFilePointerEx
$setfilepointerexmethod = $typebuilder.definemethod(
    "SetFilePointerEx",
    [system.reflection.methodattributes] "Public, Static",
    [uint32],
    [Type[]] @(
        [IntPtr],
        [uint64],
        [IntPtr],
        [uint32]
    )
)
$setfilepointerexdllimport = [system.runtime.interopservices.dllimportattribute].getconstructor(@([string]))
$setfilepointerexfieldarray = [system.reflection.fieldinfo[]] @(
     [system.runtime.interopservices.dllimportattribute].getfield("EntryPoint"),
     [system.runtime.interopservices.dllimportattribute].getfield("PreserveSig"),
     [system.runtime.interopservices.dllimportattribute].getfield("SetLastError"),
     [system.runtime.interopservices.dllimportattribute].getfield("CallingConvention"),
     [system.runtime.interopservices.dllimportattribute].getfield("CharSet")
)
$setfilepointerexfieldvaluearray = [object[]] @(
     "SetFilePointerEx",
     $true,
     $true,
     [system.runtime.interopservices.callingconvention]::winapi,
     [system.runtime.interopservices.charSet]::auto
)
$setfilepointerexcustomattribute = new-object system.reflection.emit.customattributebuilder(
     $setfilepointerexdllImport,
     @("kernel32.dll"),
     $setfilepointerexfieldarray,
     $setfilepointerexfieldvaluearray
)
$setfilepointerexmethod.setcustomattribute($setfilepointerexcustomattribute)

#ReadFile
$readfilemethod = $typebuilder.definemethod(
    "ReadFile",
    [system.reflection.methodattributes] "Public, Static",
    [uint32],
    [Type[]] @(
        [IntPtr],
        [IntPtr],
        [uint32],
        [IntPtr],
        [IntPtr]
    )
)
$readfiledllimport = [system.runtime.interopservices.dllimportattribute].getconstructor(@([string]))
$readfilefieldarray = [system.reflection.fieldinfo[]] @(
     [system.runtime.interopservices.dllimportattribute].getfield("EntryPoint"),
     [system.runtime.interopservices.dllimportattribute].getfield("PreserveSig"),
     [system.runtime.interopservices.dllimportattribute].getfield("SetLastError"),
     [system.runtime.interopservices.dllimportattribute].getfield("CallingConvention"),
     [system.runtime.interopservices.dllimportattribute].getfield("CharSet")
)
$readfilefieldvaluearray = [object[]] @(
     "ReadFile",
     $true,
     $true,
     [system.runtime.interopservices.callingconvention]::winapi,
     [system.runtime.interopservices.charSet]::auto
)
$readfilecustomattribute = new-object system.reflection.emit.customattributebuilder(
     $readfiledllImport,
     @("kernel32.dll"),
     $readfilefieldarray,
     $readfilefieldvaluearray
)
$readfilemethod.setcustomattribute($readfilecustomattribute)

#CloseHandle
$closehandlemethod = $typebuilder.definemethod(
    "CloseHandle",
    [system.reflection.methodattributes] "Public, Static",
    [uint32],
    [Type[]] @(
        [IntPtr]
    )
)
$closehandledllimport = [system.runtime.interopservices.dllimportattribute].getconstructor(@([string]))
$closehandlefieldarray = [system.reflection.fieldinfo[]] @(
     [system.runtime.interopservices.dllimportattribute].getfield("EntryPoint"),
     [system.runtime.interopservices.dllimportattribute].getfield("PreserveSig"),
     [system.runtime.interopservices.dllimportattribute].getfield("SetLastError"),
     [system.runtime.interopservices.dllimportattribute].getfield("CallingConvention"),
     [system.runtime.interopservices.dllimportattribute].getfield("CharSet")
)
$closehandlefieldvaluearray = [object[]] @(
     "CloseHandle",
     $true,
     $true,
     [system.runtime.interopservices.callingconvention]::winapi,
     [system.runtime.interopservices.charSet]::auto
)
$closehandlecustomattribute = new-object system.reflection.emit.customattributebuilder(
     $closehandledllImport,
     @("kernel32.dll"),
     $closehandlefieldarray,
     $closehandlefieldvaluearray
)
$closehandlemethod.setcustomattribute($closehandlecustomattribute)

#create kernel32 class
$Kernel32 = $typebuilder.createtype()

And I also implemented utility function. Get-multi-bytes methods (16bit 32bit 64bit) for Marshal buffer only supports signed value, so I add unsigned version to ps object.

psutil.ps1
#My Utility Functions
$myutil = new-object psobject

#properties
#$myutil | Add-Member noteproperty -name hoge -value "hoge"

$myutil | Add-Member noteproperty -name writeoption -value $false

#methods
#$myutil | add-member scriptmethod -name fuga -value { param($fuga) return $fuga }

$myutil | add-member scriptmethod -name ReadByte -value {
    param($buffer, $offset) 
    [byte]$retval = 0
    
    switch($buffer.getType().Name){
        "IntPtr"{
            $retval = [system.runtime.interopservices.marshal]::ReadByte($buffer, $offset)
        }
        "byte[]"{
            $retval = $buffer[$offset]
        }
        "Object[]"{
            $retval = $buffer[$offset]
        }
    }
    return $retval
}

$myutil | add-member scriptmethod -name ReadUInt16 -value {
    param($buffer, $offset) 

    [uint16]$retval = 0
    switch($buffer.getType().Name){
        "IntPtr"{
            for($i = 0; $i -lt 2; $i++){
                $retval += [system.runtime.interopservices.marshal]::ReadByte($buffer, $offset + $i) * [math]::pow(0x0100, $i)
            }
        }
        "byte[]"{
            for($i = 0; $i -lt 2; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
        "Object[]"{
            for($i = 0; $i -lt 2; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
    }

    return $retval
}

$myutil | add-member scriptmethod -name ReadUInt32 -value {
    param($buffer, $offset) 

    [uint32]$retval = 0
    switch($buffer.getType().Name){
        "IntPtr"{
            for($i = 0; $i -lt 4; $i++){
                $retval += [system.runtime.interopservices.marshal]::ReadByte($buffer, $offset + $i) * [math]::pow(0x0100, $i)
            }
        }
        "byte[]"{
            for($i = 0; $i -lt 4; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
        "Object[]"{
            for($i = 0; $i -lt 4; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
    }
    return $retval
}

$myutil | add-member scriptmethod -name ReadUInt64 -value {
    param($buffer, $offset) 

    [uint64]$retval = 0
    switch($buffer.getType().Name){
        "IntPtr"{
            for($i = 0; $i -lt 8; $i++){
                $retval += [system.runtime.interopservices.marshal]::ReadByte($buffer, $offset + $i) * [math]::pow(0x0100, $i)
            }
        }
        "byte[]"{
            for($i = 0; $i -lt 8; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
        "Object[]"{
            for($i = 0; $i -lt 8; $i++){
                $retval += $buffer[$offset + $i] * [math]::pow(0x0100, $i)
            }
        }
    }
    return $retval
}

$myutil | add-member scriptmethod -name Dump -value {
    param($buffer) 

    $outlen = 16
    $linenum = 0

    $output = $linenum.tostring("X8") + " : "
    $linenum++
    for($i = 0; $i -lt $buffer.count; $i++){
        $output += (($this.ReadByte($buffer,$i)).tostring("X2") + " ")
        if(($i % $outlen) -eq ($outlen - 1)){
            write-host $output
            $output = $linenum.tostring("X8") + " : "
            $linenum++
        }
    }
    write-host $output
}

$myutil | add-member scriptmethod -name write2host -value {
    param($msg) 
    if($this.writeoption){
        write-host $msg
    }
}
Profile
I have technical job experience in enbedded software development and server side infrastructure/application engineering. I'm interested in programming and computer security.
Objective
To write down my technical knowledge in the place where I can access from anywhere. To share my program source code. To train my writing skill.
Link
  • LinkedIn (preparing)

  • Twitter

  • Facebook (preparing)

  • GitHub

  • StackOverFlow (preparing)

Archives