xref: /aosp_15_r20/external/capstone/bindings/powershell/Capstone/Capstone.psm1 (revision 9a0e4156d50a75a99ec4f1653a0e9602a5d45c18)
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