1 <#
2 .SYNOPSIS
3 Get Capstone version as Version object
4 #>
Get-CapstoneVersionnull5 function Get-CapstoneVersion {
6 $Version = [System.BitConverter]::GetBytes(
7 [Capstone]::cs_version($null, $null)
8 )
9
10 New-Object -TypeName version -ArgumentList @(
11 $Version[1]
12 $Version[0]
13 0
14 0
15 )
16 }
17
18 <#
19 .SYNOPSIS
20 Create C# bindings for capstone.dll
21
22 .PARAMETER DllPath
23 Path to capstone.dll
24 #>
Initialize-Capstone()25 function Initialize-Capstone {
26 [CmdletBinding()]
27 Param (
28 [Parameter(Mandatory = $true)]
29 [ValidateScript( {
30 try {
31 Test-Path -Path $_ -PathType Leaf -ErrorAction Stop
32 } catch {
33 throw "Capstone DLL is missing: $DllPath"
34 }
35 })]
36 [ValidateNotNullOrEmpty()]
37 [string]$DllPath
38 )
39
40 # Escape path for use in inline C#
41 $DllPath = $DllPath.Replace('\', '\\')
42
43 # Inline C# to parse the unmanaged capstone DLL
44 # http://stackoverflow.com/questions/16552801/how-do-i-conditionally-add-a-class-with-add-type-typedefinition-if-it-isnt-add
45 if (-not ([System.Management.Automation.PSTypeName]'Capstone').Type) {
46 Add-Type -TypeDefinition @"
47 using System;
48 using System.Diagnostics;
49 using System.Runtime.InteropServices;
50 using System.Security.Principal;
51
52 [StructLayout(LayoutKind.Sequential)]
53 public struct cs_insn
54 {
55 public uint id;
56 public ulong address;
57 public ushort size;
58 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
59 public byte[] bytes;
60 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
61 public string mnemonic;
62 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 160)]
63 public string operands;
64 public IntPtr detail;
65 }
66
67 /// Partial, only architecture-independent internal data
68 [StructLayout(LayoutKind.Sequential)]
69 public struct cs_detail
70 {
71 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
72 public byte[] regs_read;
73 public byte regs_read_count;
74 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
75 public byte[] regs_write;
76 public byte regs_write_count;
77 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
78 public byte[] groups;
79 public byte groups_count;
80 }
81
82 public enum cs_err : int
83 {
84 CS_ERR_OK = 0, /// No error: everything was fine
85 CS_ERR_MEM, /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
86 CS_ERR_ARCH, /// Unsupported architecture: cs_open()
87 CS_ERR_HANDLE, /// Invalid handle: cs_op_count(), cs_op_index()
88 CS_ERR_CSH, /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
89 CS_ERR_MODE, /// Invalid/unsupported mode: cs_open()
90 CS_ERR_OPTION, /// Invalid/unsupported option: cs_option()
91 CS_ERR_DETAIL, /// Information is unavailable because detail option is OFF
92 CS_ERR_MEMSETUP, /// Dynamic memory management uninitialized (see CS_OPT_MEM)
93 CS_ERR_VERSION, /// Unsupported version (bindings)
94 CS_ERR_DIET, /// Access irrelevant data in "diet" engine
95 CS_ERR_SKIPDATA, /// Access irrelevant data for "data" instruction in SKIPDATA mode
96 CS_ERR_X86_ATT, /// X86 AT&T syntax is unsupported (opt-out at compile time)
97 CS_ERR_X86_INTEL, /// X86 Intel syntax is unsupported (opt-out at compile time)
98 }
99 public enum cs_arch : int
100 {
101 CS_ARCH_ARM = 0, /// ARM architecture (including Thumb, Thumb-2)
102 CS_ARCH_ARM64, /// ARM-64, also called AArch64
103 CS_ARCH_MIPS, /// Mips architecture
104 CS_ARCH_X86, /// X86 architecture (including x86 & x86-64)
105 CS_ARCH_PPC, /// PowerPC architecture
106 CS_ARCH_SPARC, /// Sparc architecture
107 CS_ARCH_SYSZ, /// SystemZ architecture
108 CS_ARCH_XCORE, /// XCore architecture
109 CS_ARCH_MAX,
110 CS_ARCH_ALL = 0xFFFF, /// All architectures - for cs_support()
111 }
112 public enum cs_mode : int
113 {
114 CS_MODE_LITTLE_ENDIAN = 0, /// little-endian mode (default mode)
115 CS_MODE_ARM = 0, /// 32-bit ARM
116 CS_MODE_16 = 1 << 1, /// 16-bit mode (X86)
117 CS_MODE_32 = 1 << 2, /// 32-bit mode (X86)
118 CS_MODE_64 = 1 << 3, /// 64-bit mode (X86, PPC)
119 CS_MODE_THUMB = 1 << 4, /// ARM's Thumb mode, including Thumb-2
120 CS_MODE_MCLASS = 1 << 5, /// ARM's Cortex-M series
121 CS_MODE_V8 = 1 << 6, /// ARMv8 A32 encodings for ARM
122 CS_MODE_MICRO = 1 << 4, /// MicroMips mode (MIPS)
123 CS_MODE_MIPS3 = 1 << 5, /// Mips III ISA
124 CS_MODE_MIPS32R6 = 1 << 6, /// Mips32r6 ISA
125 CS_MODE_MIPSGP64 = 1 << 7, /// General Purpose Registers are 64-bit wide (MIPS)
126 CS_MODE_V9 = 1 << 4, /// SparcV9 mode (Sparc)
127 CS_MODE_BIG_ENDIAN = 1 << 31, /// big-endian mode
128 CS_MODE_MIPS32 = CS_MODE_32, /// Mips32 ISA (Mips)
129 CS_MODE_MIPS64 = CS_MODE_64, /// Mips64 ISA (Mips)
130 }
131
132 public static class Capstone
133 {
134 [DllImport("$DllPath")]
135 public static extern cs_err cs_open(
136 cs_arch arch,
137 cs_mode mode,
138 ref IntPtr handle);
139
140 [DllImport("$DllPath")]
141 public static extern UInt32 cs_disasm(
142 IntPtr handle,
143 byte[] code,
144 int code_size,
145 ulong address,
146 int count,
147 ref IntPtr insn);
148
149 [DllImport("$DllPath")]
150 public static extern bool cs_free(
151 IntPtr insn,
152 int count);
153
154 [DllImport("$DllPath")]
155 public static extern cs_err cs_close(
156 ref IntPtr handle);
157
158 [DllImport("$DllPath")]
159 public static extern cs_err cs_option(
160 IntPtr handle,
161 int type,
162 int value);
163
164 [DllImport("$DllPath", CallingConvention = CallingConvention.Cdecl)]
165 public static extern IntPtr cs_reg_name(
166 IntPtr handle,
167 uint reg_id);
168
169 [DllImport("$DllPath")]
170 public static extern int cs_version(
171 uint major,
172 uint minor);
173 }
174 "@
175 } else {
176 Write-Verbose 'C# bindings are already compiled'
177 }
178 }
179
Get-CapstoneDisassembly()180 function Get-CapstoneDisassembly {
181 <#
182 .SYNOPSIS
183 Powershell wrapper for Capstone (using inline C#).
184
185 .DESCRIPTION
186 Author: Ruben Boonen (@FuzzySec), @beatcracker
187 License: BSD 3-Clause
188 Required Dependencies: None
189 Optional Dependencies: None
190
191 .PARAMETER Architecture
192 Architecture type.
193
194 .PARAMETER Mode
195 Mode type.
196
197 .PARAMETER Bytes
198 Byte array to be disassembled.
199
200 .PARAMETER Syntax
201 Syntax for output assembly.
202
203 .PARAMETER Address
204 Assign address for the first instruction to be disassembled.
205
206 .PARAMETER Detailed
207 Return detailed output.
208
209 .PARAMETER Version
210 Print ASCII version banner.
211
212 .EXAMPLE
213
214 C:\PS> $Bytes = [byte[]] @( 0x10, 0xf1, 0x10, 0xe7, 0x11, 0xf2, 0x31, 0xe7, 0xdc, 0xa1, 0x2e, 0xf3, 0xe8, 0x4e, 0x62, 0xf3 )
215 C:\PS> Get-CapstoneDisassembly -Architecture CS_ARCH_ARM -Mode CS_MODE_ARM -Bytes $Bytes
216
217 Address : 0x100000
218 Instruction : sdiv r0, r0, r1
219
220 Address : 0x100004
221 Instruction : udiv r1, r1, r2
222
223 Address : 0x100008
224 Instruction : vbit q5, q15, q6
225
226 Address : 0x10000C
227 Instruction : vcgt.f32 q10, q9, q12
228
229 .EXAMPLE
230
231 # Detailed mode & ATT syntax
232 C:\PS> $Bytes = [byte[]] @( 0xB8, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF3 )
233 C:\PS> Get-CapstoneDisassembly -Architecture CS_ARCH_X86 -Mode CS_MODE_32 -Bytes $Bytes -Syntax ATT -Detailed
234
235 Address : 0x100000
236 Mnemonic : movl
237 Operands : $0xa, %eax
238 Bytes : {184, 10, 0, 0...}
239 Size : 5
240 RegRead :
241 RegWrite :
242
243 Address : 0x100005
244 Mnemonic : divl
245 Operands : %ebx
246 Bytes : {247, 243}
247 Size : 2
248 RegRead : {eax, edx}
249 RegWrite : {eax, edx, eflags}
250
251 .EXAMPLE
252
253 # Get-CapstoneDisassembly emits objects
254 C:\PS> $Bytes = [byte[]] @( 0xB8, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF3 )
255 C:\PS> $Object = Get-CapstoneDisassembly -Architecture CS_ARCH_X86 -Mode CS_MODE_32 -Bytes $Bytes -Detailed
256 C:\PS> $Object | Select-Object -Property Size, Mnemonic, Operands
257
258 Size Mnemonic Operands
259 ---- -------- --------
260 5 mov eax, 0xa
261 2 div ebx
262 #>
263 [CmdletBinding(DefaultParameterSetName = 'Capstone')]
264 Param (
265 [Parameter(ParameterSetName = 'Capstone', Mandatory = $true)]
266 [ValidateSet(
267 'CS_ARCH_ARM',
268 'CS_ARCH_ARM64',
269 'CS_ARCH_MIPS',
270 'CS_ARCH_X86',
271 'CS_ARCH_PPC',
272 'CS_ARCH_SPARC',
273 'CS_ARCH_SYSZ',
274 'CS_ARCH_XCORE',
275 'CS_ARCH_MAX',
276 'CS_ARCH_ALL'
277 )]
278 [string]$Architecture,
279
280 [Parameter(ParameterSetName = 'Capstone', Mandatory = $true)]
281 [ValidateSet(
282 'CS_MODE_LITTLE_ENDIAN',
283 'CS_MODE_ARM',
284 'CS_MODE_16',
285 'CS_MODE_32',
286 'CS_MODE_64',
287 'CS_MODE_THUMB',
288 'CS_MODE_MCLASS',
289 'CS_MODE_V8',
290 'CS_MODE_MICRO',
291 'CS_MODE_MIPS3',
292 'CS_MODE_MIPS32R6',
293 'CS_MODE_MIPSGP64',
294 'CS_MODE_V9',
295 'CS_MODE_BIG_ENDIAN',
296 'CS_MODE_MIPS32',
297 'CS_MODE_MIPS64'
298 )]
299 [string]$Mode,
300
301 [Parameter(ParameterSetName = 'Capstone', Mandatory = $true)]
302 [ValidateNotNullOrEmpty()]
303 [byte[]]$Bytes,
304
305 [Parameter(ParameterSetName = 'Capstone')]
306 [ValidateSet(
307 'Intel',
308 'ATT'
309 )]
310 [string]$Syntax = 'Intel',
311
312 [Parameter(ParameterSetName = 'Capstone')]
313 [uint64]$Address = 0x100000,
314
315 [Parameter(ParameterSetName = 'Capstone')]
316 [switch]$Detailed,
317
318 [Parameter(ParameterSetName = 'Version')]
319 [switch]$Version
320 )
321
322 if ($Version) {
323 $Banner = @'
324
325 (((;
326 (; "((((\
327 ;((((((; "((((;
328 ((((""\(((( "((((
329 ((((" ((\ "(((( "(((\
330 ;(((/ ((((((( "(((( \(((
331 ((((" (((* "(((( \(((;"(((\
332 ((((";((("/(( \(((;"(((\"(((\
333 (((( (((( ((((" "(((\ ((() (((\
334 ;((("(((( (((* **"" ((()"(((;
335 (((" ((( (((( ((((((((((((((:*(((
336 (((( (((*)((( ********"""" ;;(((((;
337 (((* ((( (((((((((((((((((((((*"" (
338 ((("(((( """***********"""" ;;(((((
339 "" (((((((((((((((((((((((((((*""
340 """****(((((****"""
341
342 -=[Capstone Engine v{0}]=-
343
344 '@ -f (Get-CapstoneVersion).ToString(2)
345 # Mmm ASCII version banner!
346 return $Banner
347 }
348
349 # Disasm Handle
350 $DisAsmHandle = [System.IntPtr]::Zero
351
352 # Initialize Capstone with cs_open()
353 $CallResult = [Capstone]::cs_open($Architecture, $Mode, [ref]$DisAsmHandle)
354 if ($CallResult -ne 'CS_ERR_OK') {
355 if ($CallResult -eq 'CS_ERR_MODE') {
356 throw "Invalid Architecture/Mode combination: $Architecture/$Mode"
357 } else {
358 throw "cs_open error: $CallResult"
359 }
360 }
361
362 # Set disassembly syntax
363 #---
364 # cs_opt_type -> CS_OPT_SYNTAX = 1
365 #---
366 # cs_opt_value -> CS_OPT_SYNTAX_INTEL = 1
367 # -> CS_OPT_SYNTAX_ATT = 2
368 if ($Syntax -eq 'Intel') {
369 $CS_OPT_SYNTAX = 1
370 } else {
371 $CS_OPT_SYNTAX = 2
372 }
373
374 $CallResult = [Capstone]::cs_option($DisAsmHandle, 1, $CS_OPT_SYNTAX)
375 if ($CallResult -ne 'CS_ERR_OK') {
376 $CallResult = [Capstone]::cs_close([ref]$DisAsmHandle)
377 throw "cs_option error: $CallResult"
378 }
379
380 # Set disassembly detail
381 #---
382 # cs_opt_type -> CS_OPT_DETAIL = 2
383 #---
384 # cs_opt_value -> CS_OPT_ON = 3
385 # -> CS_OPT_OFF = 0
386 if ($Detailed) {
387 $CS_OPT = 3
388 } else {
389 $CS_OPT = 0
390 }
391
392 $CallResult = [Capstone]::cs_option($DisAsmHandle, 2, $CS_OPT)
393 if ($CallResult -ne 'CS_ERR_OK') {
394 $CallResult = [Capstone]::cs_close([ref]$DisAsmHandle)
395 throw "cs_option error: $CallResult"
396 }
397
398 # Out Buffer Handle
399 $InsnHandle = [System.IntPtr]::Zero
400
401 # Disassemble bytes
402 $Count = [Capstone]::cs_disasm($DisAsmHandle, $Bytes, $Bytes.Count, $Address, 0, [ref]$InsnHandle)
403
404 if ($Count -gt 0) {
405 # Result struct
406 $cs_insn = if ($PSVersionTable.PSVersion.Major -gt 2) {
407 [cs_insn]@{}
408 } else {
409 New-Object -TypeName cs_insn
410 }
411
412 $cs_insn_size = [System.Runtime.InteropServices.Marshal]::SizeOf($cs_insn)
413 $cs_insn = $cs_insn.GetType()
414
415 # Result detail struct
416 $cs_detail = if ($PSVersionTable.PSVersion.Major -gt 2) {
417 [cs_detail]@{}
418 } else {
419 New-Object -TypeName cs_detail
420 }
421 $cs_detail = $cs_detail.GetType()
422
423 # Result buffer offset
424 $BuffOffset = $InsnHandle.ToInt64()
425
426 for ($i = 0 ; $i -lt $Count ; $i++) {
427 # Cast Offset to cs_insn
428 $Cast = [System.Runtime.InteropServices.Marshal]::PtrToStructure([System.Intptr]$BuffOffset, [type]$cs_insn)
429
430 if ($CS_OPT -eq 0) {
431 $Disassembly = @{
432 Address = $Cast.address
433 Instruction = '{0} {1}' -f $Cast.mnemonic, $Cast.operands
434 }
435
436 if ($PSVersionTable.PSVersion.Major -gt 2) {
437 # Add TypeName for PS formatting and output result
438 $Disassembly.PSTypeName ='CapstoneDisassembly.Simple'
439 [pscustomobject]$Disassembly
440 } else {
441 $Disassembly = New-Object -TypeName PSObject -Property $Disassembly
442 # Add TypeName for PS formatting and output result
443 $Disassembly.PSObject.TypeNames.Insert(0, 'CapstoneDisassembly.Simple')
444 $Disassembly
445 }
446 } else {
447 $DetailCast = [System.Runtime.InteropServices.Marshal]::PtrToStructure($Cast.detail, [type]$cs_detail)
448 if ($DetailCast.regs_read_count -gt 0) {
449 $RegRead = for ($r = 0 ; $r -lt $DetailCast.regs_read_count ; $r++) {
450 $NamePointer = [Capstone]::cs_reg_name($DisAsmHandle, $DetailCast.regs_read[$r])
451 [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($NamePointer)
452 }
453 }
454
455 if ($DetailCast.regs_write_count -gt 0) {
456 $RegWrite = for ($r = 0 ; $r -lt $DetailCast.regs_write_count ; $r++) {
457 $NamePointer = [Capstone]::cs_reg_name($DisAsmHandle, $DetailCast.regs_write[$r])
458 [System.Runtime.InteropServices.Marshal]::PtrToStringAnsi($NamePointer)
459 }
460 }
461
462 $Disassembly = @{
463 Address = $Cast.address
464 Mnemonic = $Cast.mnemonic
465 Operands = $Cast.operands
466 Bytes = $Cast.bytes[0..($Cast.size - 1)]
467 Size = $Cast.size
468 RegRead = $RegRead
469 RegWrite = $RegWrite
470 }
471
472 if ($PSVersionTable.PSVersion.Major -gt 2) {
473 # Add TypeName for PS formatting and output result
474 $Disassembly.PSTypeName = 'CapstoneDisassembly.Detailed'
475 [pscustomobject]$Disassembly
476 } else {
477 $Disassembly = New-Object -TypeName PSObject -Property $Disassembly
478 # Add TypeName for PS formatting and output result
479 $Disassembly.PSObject.TypeNames.Insert(0, 'CapstoneDisassembly.Detailed')
480 $Disassembly
481 }
482 }
483 $BuffOffset = $BuffOffset + $cs_insn_size
484 }
485 } else {
486 $CallResult = [Capstone]::cs_close([ref]$DisAsmHandle)
487 throw 'Disassembly Failed'
488 }
489
490 # Free Buffer Handle
491 $CallResult = [Capstone]::cs_free($InsnHandle, $Count)
492 }
493
494 #region Init
495
496 Initialize-Capstone -DllPath (
497 Join-Path -Path $PSScriptRoot -ChildPath 'Lib\Capstone\capstone.dll'
498 ) -ErrorAction Stop
499
500 #endregion