Skip to content

Commit 385e27e

Browse files
authored
Add files via upload
0 parents  commit 385e27e

File tree

6 files changed

+502
-0
lines changed

6 files changed

+502
-0
lines changed

Get-PDInvokeImports.ps1

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
<#
2+
.SYNOPSIS
3+
Author: Dump-GUY (@vinopaljiri)
4+
Get-PDInvokeImports is tool which is able to detect P/Invoke, Dynamic P/Invoke and D/Invoke used in assembly.
5+
It uses dnlib to parse assembly and .NET reflection to load dnlib.
6+
This PS module could be useful and helpful during reversing .NET assemblies for fast revealing calls to unmanaged API functions used in assembly.
7+
Sometimes malware assemblies are full of junk code where the main functionality is implemeted by direct WIN API or NTAPI calls.
8+
9+
.DESCRIPTION
10+
Get-PDInvokeImports enables you to get fast overview what P/Invoke, Dynamic P/Invoke and D/Invoke are used in assembly.
11+
It will show you what functions are used + MDTokens, where are declared, and all location where are used from code.
12+
This PS module enables you to export all locations where are detected P/Invoke, Dynamic P/Invoke and D/Invokereferenced from code to DnSpy Bookmarks.xml
13+
Example: Imagine 1MB assembly full of junk code + CF obfuscation where main functionality is reached via unmanaged WinAPI\NTAPI calls.
14+
15+
.PARAMETER PathToAssembly
16+
Mandatory parameter.
17+
Specifies the Assembly path to scan.
18+
19+
.PARAMETER PathToDnlib
20+
Optional parameter.
21+
System Path to dnlib.dll.
22+
If powershell is running from the location of dnlib.dll - this parameter could be ignored otherwise specify this parameter.
23+
24+
.PARAMETER ExportDnSpyBookmarks
25+
Optional parameter.
26+
Used to export all detected P/Invoke, Dynamic P/Invoke and D/Invoke locations referenced from code to DnSpy Bookmarks XML file (DnSpy_Bookmarks.xml)
27+
Similar to DnSpy-Analyze-UsedBy (Nice overview where all PInvoke and DInvoke are used in whole code)
28+
So it is possible to import it to DnSpy via Bookmarks Window
29+
30+
.EXAMPLE
31+
PS> Import-Module .\Get-PDInvokeImports.ps1
32+
PS> Get-PDInvokeImports -PathToAssembly 'C:\testfiles\malware.exe' -PathToDnlib "C:\dnlib.dll" -ExportDnSpyBookmarks
33+
PS> Get-PDInvokeImports -PathToAssembly 'C:\testfiles\malware.exe'
34+
PS> Get-PDInvokeImports -PathToAssembly .\malware.exe -ExportDnSpyBookmarks
35+
36+
.LINK
37+
https://github.com/Dump-GUY/Get-PDInvokeImports
38+
https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke
39+
https://github.com/TheWover/DInvoke
40+
https://bohops.com/2022/04/02/unmanaged-code-execution-with-net-dynamic-pinvoke/
41+
https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.typebuilder.definepinvokemethod?view=netframework-4.6.1
42+
#>
43+
function Get-PDInvokeImports
44+
{
45+
[CmdletBinding()]
46+
param
47+
(
48+
[Parameter(Mandatory = $true)]
49+
[ValidateNotNullOrEmpty()]
50+
[string]$PathToAssembly,
51+
52+
[Parameter(Mandatory = $false)]
53+
[string]$PathToDnlib = [System.Environment]::CurrentDirectory + "\dnlib.dll",
54+
55+
[Parameter(Mandatory = $false)]
56+
[switch]$ExportDnSpyBookmarks = $false
57+
)
58+
59+
#DInvoke imports reveal - type filter
60+
function Get_DInvoke_Types($AllTypes)
61+
{
62+
foreach($type in $AllTypes)
63+
{
64+
#get only types which have CustomAttribute = UnmanagedFunctionPointerAttribute and are defined as CallingConvention.StdCall or CallingConvention.Winapi or also possible CallingConvention.Cdecl
65+
if(("UnmanagedFunctionPointerAttribute" -in $type.CustomAttributes.AttributeType.Name.String) -and ("CallingConvention" -in $type.CustomAttributes.ConstructorArguments.type.TypeName) -and ($type.CustomAttributes.ConstructorArguments.Value -in @(1,2,3)))
66+
{
67+
[System.Object[]]$DInvoke_Types += $type
68+
}
69+
}
70+
return $DInvoke_Types
71+
}
72+
#DInvoke imports - add all Used by methods
73+
function Get_DInvoke_ALL($DInvoke_Types, $All_Types)
74+
{
75+
foreach($DinvokeType in $DInvoke_Types)
76+
{
77+
foreach($type in $All_Types)
78+
{
79+
foreach($method in $type.Methods)
80+
{
81+
if($DinvokeType.FullName -in $method.MethodBody.Instructions.operand.fullname)
82+
{
83+
[System.Object[]]$DInvoke_UsedBy += $method
84+
}
85+
}
86+
}
87+
Add-Member -InputObject $DinvokeType -NotePropertyName "Used By Methods MDTokens" -NotePropertyValue $DInvoke_UsedBy.MDToken
88+
Add-Member -InputObject $DinvokeType -NotePropertyName "Used By Methods" -NotePropertyValue $DInvoke_UsedBy.FullName
89+
[System.Object[]]$DInvoke_All += $DinvokeType
90+
if($DInvoke_UsedBy)
91+
{
92+
Clear-Variable -Name DInvoke_UsedBy
93+
}
94+
}
95+
return $DInvoke_All
96+
}
97+
#PInvoke imports reveal - Methods filter
98+
function Get_PInvoke_Methods($AllTypes)
99+
{
100+
foreach($type in $AllTypes)
101+
{
102+
foreach($method in $type.Methods)
103+
{ #get only Methods with PinvokeImpl attribute
104+
if($method.Attributes.value__ -band [dnlib.DotNet.MethodAttributes]::PinvokeImpl.value__)
105+
{
106+
[System.Object[]]$PInvoke_Methods += $method
107+
}
108+
}
109+
}
110+
return $PInvoke_Methods
111+
}
112+
#PInvoke imports - add all Used by methods
113+
function Get_PInvoke_ALL($PInvoke_methods, $All_Types)
114+
{
115+
foreach($PinvokeMethod in $PInvoke_methods)
116+
{
117+
foreach($type in $All_Types)
118+
{
119+
foreach($method in $type.Methods)
120+
{
121+
if($PinvokeMethod.FullName -in $method.MethodBody.Instructions.operand.fullname)
122+
{
123+
[System.Object[]]$PInvoke_UsedBy += $method
124+
}
125+
}
126+
}
127+
Add-Member -InputObject $PinvokeMethod -NotePropertyName "Used By Methods MDTokens" -NotePropertyValue $PInvoke_UsedBy.MDToken
128+
Add-Member -InputObject $PinvokeMethod -NotePropertyName "Used By Methods" -NotePropertyValue $PInvoke_UsedBy.FullName
129+
[System.Object[]]$PInvoke_All += $PinvokeMethod
130+
if($PInvoke_UsedBy)
131+
{
132+
Clear-Variable -Name PInvoke_UsedBy
133+
}
134+
}
135+
return $PInvoke_All
136+
}
137+
138+
#Dynamic PInvoke imports reveal - Methods filter which are implementing DefinePInvokeMethod
139+
function Get_PInvoke_Dynamic_Methods($AllTypes)
140+
{
141+
foreach($type in $AllTypes)
142+
{
143+
foreach($method in $type.Methods)
144+
{
145+
if($method.MethodBody.Instructions.operand.fullname -match 'DefinePInvokeMethod')
146+
{
147+
[System.Object[]]$PInvokeDynamic_methods += $method
148+
}
149+
}
150+
}
151+
return $PInvokeDynamic_methods
152+
}
153+
154+
#Dynamic PInvoke imports - add all Used by methods
155+
function Get_PInvoke_Dynamic_ALL($PInvokeDynamic_Methods, $All_Types)
156+
{
157+
foreach($PinvokeDynamicMethod in $PInvokeDynamic_Methods)
158+
{
159+
foreach($type in $All_Types)
160+
{
161+
foreach($method in $type.Methods)
162+
{
163+
if($PinvokeDynamicMethod.FullName -in $method.MethodBody.Instructions.operand.fullname)
164+
{
165+
[System.Object[]]$PInvokeDynamic_UsedBy += $method
166+
}
167+
}
168+
}
169+
Add-Member -InputObject $PinvokeDynamicMethod -NotePropertyName "Used By Methods MDTokens" -NotePropertyValue $PInvokeDynamic_UsedBy.MDToken
170+
Add-Member -InputObject $PinvokeDynamicMethod -NotePropertyName "Used By Methods" -NotePropertyValue $PInvokeDynamic_UsedBy.FullName
171+
[System.Object[]]$PInvokeDynamic_ALL += $PinvokeDynamicMethod
172+
if($PInvokeDynamic_UsedBy)
173+
{
174+
Clear-Variable -Name PInvokeDynamic_UsedBy
175+
}
176+
}
177+
return $PInvokeDynamic_ALL
178+
}
179+
180+
#Export detected PInvoke, Dynamic PInvoke and Dinvoke to DnSpy bookmarks XML file - all location where they are referenced (similar to DnSpy-Analyze-UsedBy)
181+
function Get_DnSpy_BookmarksXML($PInvoke_ALL, $PInvokeDynamic_ALL, $DInvoke_ALL, $All_Types)
182+
{
183+
$xmltemplate_start = @"
184+
<?xml version="1.0" encoding="utf-8"?>
185+
<settings>
186+
<section _="eaa1be38-7a55-44af-ad93-5b7ee2327edd">
187+
188+
"@
189+
$xmltemplate_end = @"
190+
</section>
191+
</settings>
192+
"@
193+
#PInvoke part
194+
$counter = 1
195+
foreach($PInvoke in $PInvoke_ALL)
196+
{
197+
foreach($type in $All_Types)
198+
{
199+
foreach($method in $type.Methods)
200+
{
201+
if($PInvoke.FullName -in $method.MethodBody.Instructions.operand.fullname)
202+
{
203+
for($i = 0; $i -lt $method.MethodBody.Instructions.count; $i++)
204+
{
205+
if($PInvoke.FullName -in $method.MethodBody.Instructions[$i].operand.fullname)
206+
{
207+
$xmltemplate_body += @"
208+
<section _="Bookmark" IsEnabled="True" Name="PInvoke$($counter)_$($PInvoke.Name.String)">
209+
<section _="BML" __BMT="DotNetBody" AssemblyFullName="$($method.Module.Assembly.FullName)" ModuleName="$($method.Module.Location)" Offset="$($method.MethodBody.Instructions[$i].offset)" Token="$($method.MDToken.Raw)" TokenString="$([System.Net.WebUtility]::HtmlEncode($method.FullName))" />
210+
</section>
211+
212+
"@
213+
$counter++
214+
}
215+
}
216+
}
217+
}
218+
}
219+
}
220+
#Dynamic PInvoke part
221+
$counter = 1
222+
foreach($PInvokeDynamic in $PInvokeDynamic_ALL)
223+
{
224+
foreach($type in $All_Types)
225+
{
226+
foreach($method in $type.Methods)
227+
{
228+
if($PInvokeDynamic.FullName -in $method.MethodBody.Instructions.operand.fullname)
229+
{
230+
for($i = 0; $i -lt $method.MethodBody.Instructions.count; $i++)
231+
{
232+
if($PInvokeDynamic.FullName -in $method.MethodBody.Instructions[$i].operand.fullname)
233+
{
234+
$xmltemplate_body += @"
235+
<section _="Bookmark" IsEnabled="True" Name="DynamicPInvoke$($counter)_$($PInvokeDynamic.Name.String)">
236+
<section _="BML" __BMT="DotNetBody" AssemblyFullName="$($method.Module.Assembly.FullName)" ModuleName="$($method.Module.Location)" Offset="$($method.MethodBody.Instructions[$i].offset)" Token="$($method.MDToken.Raw)" TokenString="$([System.Net.WebUtility]::HtmlEncode($method.FullName))" />
237+
</section>
238+
239+
"@
240+
$counter++
241+
}
242+
}
243+
}
244+
}
245+
}
246+
}
247+
#DInvoke part
248+
$counter = 1
249+
foreach($DInvoke in $DInvoke_ALL)
250+
{
251+
foreach($type in $All_Types)
252+
{
253+
foreach($method in $type.Methods)
254+
{
255+
if($DInvoke.FullName -in $method.MethodBody.Instructions.operand.fullname)
256+
{
257+
for($i = 0; $i -lt $method.MethodBody.Instructions.count; $i++)
258+
{
259+
if($DInvoke.FullName -in $method.MethodBody.Instructions[$i].operand.fullname)
260+
{
261+
$xmltemplate_body += @"
262+
<section _="Bookmark" IsEnabled="True" Name="DInvoke$($counter)_$($DInvoke.Name.String)">
263+
<section _="BML" __BMT="DotNetBody" AssemblyFullName="$($method.Module.Assembly.FullName)" ModuleName="$($method.Module.Location)" Offset="$($method.MethodBody.Instructions[$i].offset)" Token="$($method.MDToken.Raw)" TokenString="$([System.Net.WebUtility]::HtmlEncode($method.FullName))" />
264+
</section>
265+
266+
"@
267+
$counter++
268+
}
269+
}
270+
}
271+
}
272+
}
273+
}
274+
return ($xmltemplate_start + $xmltemplate_body + $xmltemplate_end)
275+
}
276+
277+
##################################### MAIN PART #####################################
278+
#loading dnlib.dll via reflection
279+
if(Test-Path -Path $PathToDnlib -PathType Leaf)
280+
{
281+
[System.Reflection.Assembly]::LoadFile($PathToDnlib) | Out-Null
282+
}
283+
else
284+
{
285+
Write-Host "'dnlib.dll' not found in current or specified directory !!!`n" -ForegroundColor Red
286+
Break
287+
}
288+
289+
#creating moduledef for sepcified assembly path
290+
if(Test-Path -Path $PathToAssembly -PathType Leaf)
291+
{
292+
$ModuleDefMD = [dnlib.DotNet.ModuleDefMD]::Load($PathToAssembly)
293+
}
294+
else
295+
{
296+
Write-Host "'PathToAssembly' error!!! Assembly not found in specified directory !!!`n" -ForegroundColor Red
297+
Break
298+
}
299+
#getting ALL Types
300+
#warning - $ModuleDefMD.Types - doesnt give all nested -> use $ModuleDefMD.GetTypes() -gives ALL
301+
$All_Types = $ModuleDefMD.GetTypes()
302+
##################################### MAIN PART #####################################
303+
304+
##################################### PINVOKE PART #####################################
305+
306+
Write-Host "Found PInvoke Imports:" -ForegroundColor Green
307+
#getting only potential Methods used for PInvoke - filtering
308+
[System.Object[]]$PInvoke_Methods = Get_PInvoke_Methods -AllTypes $All_Types
309+
if($PInvoke_Methods)
310+
{
311+
#getting all methods where PInvoke is used add them as property
312+
[System.Object[]]$PInvoke_ALL = Get_PInvoke_ALL -PInvoke_methods $PInvoke_Methods -All_Types $All_Types
313+
#result -> potential PInvoke imports
314+
$PInvoke_ALL | Select-Object -Property Name, MDToken, DeclaringType, "Used By Methods", "Used By Methods MDTokens"
315+
}
316+
else
317+
{
318+
Write-Host "NONE`n" -ForegroundColor Red
319+
}
320+
321+
##################################### PINVOKE PART #####################################
322+
323+
##################################### DYNAMIC PINVOKE PART #####################################
324+
325+
Write-Host "Found Dynamic PInvoke Imports:" -ForegroundColor Green
326+
#getting only potential Methods using Dynamic PInvoke (DefinePInvokeMethod) - filtering
327+
[System.Object[]]$PInvokeDynamic_Methods = Get_PInvoke_Dynamic_Methods -AllTypes $All_Types
328+
if($PInvokeDynamic_Methods)
329+
{
330+
#getting all methods where Dynamic PInvoke is used add them as property
331+
[System.Object[]]$PInvokeDynamic_ALL = Get_PInvoke_Dynamic_ALL -PInvokeDynamic_Methods $PInvokeDynamic_Methods -All_Types $All_Types
332+
#result -> potential Dynamic PInvoke imports
333+
$PInvokeDynamic_ALL | Select-Object -Property Name, MDToken, DeclaringType, "Used By Methods", "Used By Methods MDTokens"
334+
}
335+
else
336+
{
337+
Write-Host "NONE`n" -ForegroundColor Red
338+
}
339+
340+
##################################### DYNAMIC PINVOKE PART #####################################
341+
342+
##################################### DINVOKE PART #####################################
343+
Write-Host "Found DInvoke Imports:" -ForegroundColor Green
344+
#getting only potential types used for DInvoke - filtering
345+
[System.Object[]]$DInvoke_Types = Get_DInvoke_Types -AllTypes $All_Types
346+
if($DInvoke_Types)
347+
{
348+
#getting all methods where DInvoke is used add them as property
349+
[System.Object[]]$DInvoke_ALL = Get_DInvoke_ALL -DInvoke_Types $DInvoke_Types -All_Types $All_Types
350+
#result -> potential DInvoke imports
351+
$DInvoke_ALL | Select-Object -Property Name, MDToken, DeclaringType, "Used By Methods", "Used By Methods MDTokens"
352+
}
353+
else
354+
{
355+
Write-Host "NONE`n" -ForegroundColor Red
356+
}
357+
##################################### DINVOKE PART #####################################
358+
#Export all used PInvoke, Dynamic PInvoke and DInvoke to DnSpy bookmarks XML file - contains all methods location where they are used
359+
if($ExportDnSpyBookmarks)
360+
{
361+
$BookmarksXML = Get_DnSpy_BookmarksXML -PInvoke_ALL $PInvoke_ALL -PInvokeDynamic_ALL $PInvokeDynamic_ALL -DInvoke_ALL $DInvoke_ALL -All_Types $All_Types
362+
Set-Content -Path .\DnSpy_Bookmarks.xml -Value $BookmarksXML -Encoding UTF8
363+
}
364+
#Cleanup Vars
365+
if($PInvoke_Methods)
366+
{
367+
Clear-Variable -Name PInvoke_Methods, PInvoke_ALL
368+
}
369+
if($PInvokeDynamic_Methods)
370+
{
371+
Clear-Variable -Name PInvokeDynamic_Methods, PInvokeDynamic_ALL
372+
}
373+
if($DInvoke_Types)
374+
{
375+
Clear-Variable -Name DInvoke_Types, DInvoke_ALL
376+
}
377+
378+
}
172 KB
Loading
205 KB
Loading
118 KB
Loading
265 KB
Loading

0 commit comments

Comments
 (0)