├── Get-SessionAnomaly.ps1 ├── Get-ShellContent.ps1 ├── README.md └── Strings2Managed ├── AssemblyInfo.cpp ├── DynArray.h ├── Release └── Strings2Managed.dll ├── Stdafx.cpp ├── Stdafx.h ├── Strings2Managed.sln ├── Strings2Managed.v12.suo ├── Strings2Managed.vcxproj ├── Strings2Managed.vcxproj.filters ├── Strings2Managed.vcxproj.user ├── Strings2ManagedWrapper.cpp ├── Strings2ManagedWrapper.h ├── basics.cpp ├── basics.h ├── dirent.h ├── module.cpp ├── module.h ├── print_buffer.cpp ├── print_buffer.h ├── process_strings.cpp ├── process_strings.h ├── resource.h ├── string_parser.cpp ├── string_parser.h ├── strings2.cpp ├── strings2.h ├── targetver.h └── x64 └── Release └── Strings2Managed.dll /Get-SessionAnomaly.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SessionsAnomaly 2 | { 3 | <# 4 | .SYNOPSIS 5 | This script will determine the existence of Pass-The-Ticket and Pass-The-Hash attacks. 6 | Can be also used to analyze current cached kerberos tickets on remote or local machine. 7 | 8 | Function: Get-SessionsAnomaly 9 | Author: Eyal Neemany (@Zwiitzer). http://www.javelin-networks.com 10 | License: https://opensource.org/licenses/BSD-3-Clause 11 | Required Dependencies: None 12 | Optional Dependencies: None 13 | Version: 1.2 14 | 15 | .PARAMETER PTT 16 | Specify if you want to detect PTT anomaly 17 | .PARAMETER PTH 18 | Specify if you want to detect PTH anomaly 19 | .PARAMETER ComputerName 20 | Specify the target endpoint to run this script on (Requires WinRM) 21 | .NOTES 22 | Run this script on endpoint you suspect to be infected, or involved in attack. 23 | Not specifying PTT or PTH flag will return both 24 | .Example 25 | Get-SessionAnomaly -PTT -PTH | ft -auto 26 | Get-SessionAnomaly -ComputerName "W10-WannaFry" | ft -auto 27 | #> 28 | Param( 29 | [switch]$PTT, 30 | [switch]$PTH, 31 | [string]$ComputerName="localhost" 32 | ) 33 | 34 | $asciiart = @" 35 | _____ _ _____ _ 36 | | __|___ ___ ___|_|___ ___| _ |___ ___ _____ ___| |_ _ 37 | |__ | -_|_ -|_ -| | . | | | | . | | .'| | | | 38 | |_____|___|___|___|_|___|_|_|__|__|_|_|___|_|_|_|__,|_|_ | 39 | |___| 40 | Eyal Neemany @Zwiitzer V 1.2 41 | http://jblog.javelin-networks.com/blog 42 | 43 | "@ 44 | 45 | if(!$PTT -and !$PTH) 46 | { 47 | $PTT = $true 48 | $PTH = $true 49 | } 50 | write-host $asciiart -ForegroundColor White 51 | if($ComputerName -ne "localhost") 52 | { 53 | Write-Host "Intiating Remote Connection with" $computerName -ForegroundColor White 54 | return ((Invoke-Command -ComputerName $ComputerName -ScriptBlock ${function:Invoke-Sessions} -ArgumentList $PTT,$PTH) | select SessionAccount,TicketClient,ServiceTicket,LogonIdHex,LogonIdDec,Injected) 55 | } 56 | else 57 | { 58 | return (Invoke-Sessions -PTT $PTT -PTH $PTH | select SessionAccount,TicketClient,ServiceTicket,LogonIdHex,LogonIdDec,Injected) 59 | } 60 | } 61 | 62 | Function Invoke-Sessions 63 | { 64 | <# 65 | .SYNOPSIS 66 | This script will determine the existence of Pass-The-Ticket and Pass-The-Hash attacks. 67 | .PARAMETER PTT 68 | Specify if you want to detect PTT anomaly 69 | .PARAMETER PTH 70 | Specify if you want to detect PTH anomaly 71 | .NOTES 72 | Run this script on endpoint you suspect to be infected, or involved in attack. 73 | Not specifying PTT or PTH flag will return both 74 | .DESCRIPTION 75 | Usage : 76 | Get-SessionAnomaly -PTT $true 77 | Get-SessionAnomaly -PTH $true -PTT $true 78 | #> 79 | Param( 80 | [bool]$PTT=$false, 81 | [bool]$PTH=$false 82 | ) 83 | ## Data Gathering 84 | $LOU = Get-WmiObject Win32_LoggedOnUser 85 | $LOS_B = Get-WmiObject Win32_LogonSession 86 | $PTH_S = $LOS_B | Where-Object {$_.AuthenticationPackage -eq 'Negotiate' -and $_.LogonType -eq '9'} 87 | $LOS = $LOS_B | Where-Object {$_.AuthenticationPackage -ne 'NTLM'} 88 | $LOS_S = $LOS | Select LogonId, AuthenticationPackage, LogonType, StartTime 89 | $KLIST = $LOS | ForEach-Object {klist.exe -li ([Convert]::ToString($_.LogonId, 16))} 90 | $klistcurrent = klist 91 | 92 | ## Object Creating 93 | $ResObj = @() 94 | $TckObj = @() 95 | $SusObj = @() 96 | $PTHObj = @() 97 | 98 | ## Parsing 99 | $rgx1 = "Name=\\`"`([\w-_\d]+`)\\[\w\W]*LogonId=\\`"`(\d+)\\`"" 100 | $rgx2 = "Targeted LogonId is 0:`(0x[\w\d]{1,9}`)" 101 | $rgx4 = "Current LogonId is 0:`(0x[\w\d]{1,9}`)" 102 | $rgx3 = "#[\d]{1,3}>\s+Client:\s`([\d\w-_`$]+`)" 103 | $rgxService = "\s+Server:\s`([.\w\d/-]+`)" 104 | foreach ($obj in $LOU) 105 | { 106 | $data=$obj.__PATH 107 | $match1 = $data -match $rgx1 108 | $Object = New-Object PSObject 109 | $Object | add-member Noteproperty idDec $Matches[2] 110 | $Object | add-member Noteproperty Account $Matches[1] 111 | $ResObj += $Object 112 | } 113 | ## Injected Tickets Detection 114 | for ($i=0; $i -lt $Klist.length;$i++) 115 | { 116 | $line=$Klist[$i] 117 | if ($line -match $rgx2) 118 | { 119 | $LogonIdDec = [convert]::toint32($Matches[1],16) 120 | $LogonIdHex = $Matches[1] 121 | } 122 | if ($line -match $rgx3) 123 | { 124 | $SessionAccount = "" 125 | $TicketClient = $Matches[1] 126 | $SessionAccount = ($ResObj | Where-Object {$_.idDec -like $LogonIdDec}).Account | Select -First 1 127 | $match4 = $klist[$i+1] -match $rgxService 128 | $ServiceTicket = $Matches[1] 129 | $ObjectB = New-Object PSObject 130 | $ObjectB | add-member Noteproperty SessionAccount $SessionAccount 131 | $ObjectB | add-member Noteproperty TicketClient $TicketClient 132 | $ObjectB | add-member Noteproperty ServiceTicket $ServiceTicket 133 | $ObjectB | add-member Noteproperty LogonIdHex $LogonIdHex 134 | $ObjectB | add-member Noteproperty LogonIdDec $LogonIdDec 135 | $ObjectB | add-member Noteproperty Injected "No" 136 | $TckObj += $ObjectB 137 | } 138 | } 139 | 140 | ## Current SessionInjected Tickets Detection 141 | for ($i=0; $i -lt $klistcurrent.length;$i++) 142 | { 143 | $line=$klistcurrent[$i] 144 | if ($line -match $rgx4) 145 | { 146 | $LogonIdDec = [convert]::toint32($Matches[1],16) 147 | $LogonIdHex = $Matches[1] 148 | } 149 | if ($line -match $rgx3) 150 | { 151 | $SessionAccount = "" 152 | $TicketClient = $Matches[1] 153 | $SessionAccount = ($ResObj | Where-Object {$_.idDec -like $LogonIdDec}).Account | Select -First 1 154 | $match4 = $klistcurrent[$i+1] -match $rgxService 155 | $ServiceTicket = $Matches[1] 156 | $ObjectB = New-Object PSObject 157 | $ObjectB | add-member Noteproperty SessionAccount $SessionAccount 158 | $ObjectB | add-member Noteproperty TicketClient $TicketClient 159 | $ObjectB | add-member Noteproperty ServiceTicket $ServiceTicket 160 | $ObjectB | add-member Noteproperty LogonIdHex $LogonIdHex 161 | $ObjectB | add-member Noteproperty LogonIdDec $LogonIdDec 162 | $ObjectB | add-member Noteproperty Injected "No" 163 | $TckObj += $ObjectB 164 | } 165 | } 166 | 167 | ## Colored Results 168 | $RedYes = Write-Output "Yes" -ForegroundColor Red 169 | 170 | ## Suspicous Objects Corrolation Print 171 | foreach ($obj in $TckObj) 172 | { 173 | if ($obj.SessionAccount -ne $null -and $obj.SessionAccount -ne $obj.TicketClient -and $obj.TicketClient -notlike "*$") 174 | { 175 | $obj.Injected = "Yes" 176 | } 177 | if ($obj.TicketClient -like "*$" -and $obj.SessionAccount -ne $null -and $obj.SessionAccount -notlike "SYSTEM" -and $obj.SessionAccount -notlike "LOCAL SERVICE" -and $obj.SessionAccount -notlike "NETWORK SERVICE" -and $obj.SessionAccount -notlike "ANONYMOUS LOGON") 178 | { 179 | $obj.Injected = "Yes" 180 | } 181 | } 182 | 183 | ##PTH Object Creation 184 | if($PTH_S -ne $null) 185 | { 186 | foreach ($obj in $PTH_S) 187 | { 188 | $SessionAccount = ($ResObj | Where-Object {$_.idDec -like $obj.LogonId}).Account 189 | $ObjectC = New-Object PSObject 190 | $ObjectC | add-member Noteproperty SessionAccount $SessionAccount 191 | $ObjectC | add-member Noteproperty LogonIdDec $obj.LogonId 192 | $ObjectC | add-member Noteproperty Injected "PTH Attack" 193 | $PTHObj += $ObjectC 194 | } 195 | } 196 | if($PTT) 197 | { 198 | $TckObj 199 | } 200 | if($PTH) 201 | { 202 | $PTHObj 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Collection of Microsoft PowerShell modules that can be used to aid with forensics of domain based attacks on an infected host. 2 | 3 | ## CodeExecution 4 | 5 | **Execute code on a target machine using Import-Module.** 6 | 7 | 8 | #### `Get-ShellContent` 9 | 10 | Extracts live input and output of any commandline process, running or dumped, encrypted or plaintext from a remote computer. 11 | 12 | 13 | #### `Get-SessionsAnomaly` 14 | 15 | Finds existence of Pass-The-Ticket and Pass-The-Hash attacks on a remote machine. 16 | 17 | ## License 18 | 19 | The IT-Tools project and all individual scripts are under the [BSD 3-Clause license] unless explicitly noted otherwise. 20 | 21 | ## Usage 22 | 23 | To install any of these modules, drop the powershell scripts into a directory and type `Import-Module PathTo\scriptName.ps1` 24 | 25 | Then run the Module from the Powershell. 26 | 27 | Refer to the comment-based help in each individual script for detailed usage information. 28 | -------------------------------------------------------------------------------- /Strings2Managed/AssemblyInfo.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavelinNetworks/IR-Tools/1e82e9592a3f5893ba39965f5d44404ddf43e697/Strings2Managed/AssemblyInfo.cpp -------------------------------------------------------------------------------- /Strings2Managed/DynArray.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // DynArray.h: interface&implementation for the DynArray class 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #ifndef _AE_DYNARRAY_H_INCLUDED_ 6 | #define _AE_DYNARRAY_H_INCLUDED_ 7 | 8 | #include 9 | 10 | template 11 | class DynArray 12 | { 13 | public: 14 | DynArray(); // constructor 15 | DynArray(const DynArray &a); // copy constructor 16 | ~DynArray(); // distructor 17 | DynArray& operator = (const DynArray &a); // assignment operator 18 | 19 | el& operator [] (unsigned int index); // get array item 20 | void Add(const el &item); // Add item to the end of array 21 | 22 | unsigned int GetSize(); // get size of array (elements) 23 | void SetSize(unsigned int newsize); // set size of array (elements) 24 | void Clear(); // clear array 25 | void Delete(unsigned int pos); // delete array item 26 | void* getptr(); // get void* pointer to array data 27 | 28 | enum exception { MEMFAIL }; // exception enum 29 | 30 | private: 31 | el *array; // pointer for array's memory 32 | unsigned int size; // size of array (elemets) 33 | unsigned int realsize; // actual size of allocated memory 34 | 35 | const static int dyn_array_step = 128; // initial size of array memory (elements) 36 | const static int dyn_array_mult = 2; // multiplier (enlarge array memory 37 | // dyn_array_mult times ) 38 | }; 39 | 40 | ////////////////////////////////////////////////////////////////////// 41 | 42 | template 43 | DynArray::DynArray() 44 | { 45 | realsize = dyn_array_step; // First, allocate step 46 | // for dyn_array_step items 47 | size = 0; 48 | array = (el *)malloc(realsize*sizeof(el)); 49 | 50 | if (array == NULL) 51 | throw MEMFAIL; 52 | } 53 | 54 | 55 | template 56 | DynArray::~DynArray() 57 | { 58 | if (array) 59 | { 60 | free(array); 61 | array = NULL; 62 | } 63 | } 64 | 65 | 66 | template 67 | DynArray::DynArray(const DynArray &a) 68 | { 69 | array = (el *)malloc(sizeof(el)*a.realsize); 70 | if (array == NULL) 71 | throw MEMFAIL; 72 | 73 | memcpy(array, a.array, sizeof(el)*a.realsize); 74 | realsize = a.realsize; 75 | size = a.size; 76 | } 77 | 78 | 79 | template 80 | DynArray& DynArray::operator = (const DynArray &a) 81 | { 82 | if (this == &a) // in case somebody tries assign array to itself 83 | return *this; 84 | 85 | if (a.size == 0) // is other array is empty -- clear this array 86 | Clear(); 87 | 88 | SetSize(a.size); // set size 89 | 90 | memcpy(array, a.array, sizeof(el)*a.size); 91 | 92 | return *this; 93 | } 94 | 95 | template 96 | unsigned int DynArray::GetSize() 97 | { 98 | return size; // simply return size 99 | } 100 | 101 | 102 | template 103 | void DynArray::SetSize(unsigned int newsize) 104 | { 105 | size = newsize; 106 | 107 | if (size != 0) 108 | { 109 | // change array memory size 110 | // if new size is larger than current 111 | // or new size is less then half of the current 112 | if ((size > realsize) || (size < realsize/2)) 113 | { 114 | realsize = size; 115 | array = (el *)realloc(array, sizeof(el)*size); 116 | 117 | if (array == NULL) 118 | throw MEMFAIL; 119 | } 120 | } 121 | else 122 | Clear(); 123 | } 124 | 125 | template 126 | void DynArray::Delete(unsigned int pos) 127 | { 128 | if (size == 1) // If array has only one element 129 | Clear(); // than we clear it, since it will be deleted 130 | else 131 | { 132 | // otherwise, shift array elements 133 | for(unsigned int i=pos; i 142 | void DynArray::Clear() // clear array memory 143 | { 144 | size = 0; 145 | array = (el *)realloc(array, sizeof(el)*dyn_array_step); 146 | // set initial memory size again 147 | realsize = dyn_array_step; 148 | } 149 | 150 | template 151 | void* DynArray::getptr() 152 | { 153 | return array; // return void* pointer 154 | } 155 | 156 | template 157 | el& DynArray::operator [] (unsigned int index) 158 | { 159 | return array[index]; // return array element 160 | } 161 | 162 | template 163 | void DynArray::Add(const el &item) 164 | { 165 | size++; 166 | 167 | if (size > realsize) 168 | { 169 | realsize *= dyn_array_mult; 170 | 171 | array = (el *)realloc(array, sizeof(el)*realsize); 172 | 173 | if (array == NULL) 174 | throw MEMFAIL; 175 | } 176 | 177 | array[size-1] = item; 178 | } 179 | 180 | #endif // ifndef _AE_DYNARRAY_H_INCLUDED_ -------------------------------------------------------------------------------- /Strings2Managed/Release/Strings2Managed.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavelinNetworks/IR-Tools/1e82e9592a3f5893ba39965f5d44404ddf43e697/Strings2Managed/Release/Strings2Managed.dll -------------------------------------------------------------------------------- /Strings2Managed/Stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, 3 | // but are changed infrequently 4 | 5 | #include "stdafx.h" 6 | -------------------------------------------------------------------------------- /Strings2Managed/Stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, 3 | // but are changed infrequently 4 | 5 | #pragma once 6 | 7 | #include "targetver.h" 8 | 9 | #include 10 | #include 11 | #include 12 | -------------------------------------------------------------------------------- /Strings2Managed/Strings2Managed.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Strings2Managed", "Strings2Managed.vcxproj", "{7DEA2454-385C-414C-8965-5D11DD9195D7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|Win32 = Debug|Win32 12 | Debug|x64 = Debug|x64 13 | Release|ARM = Release|ARM 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|ARM.ActiveCfg = Debug|ARM 19 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|ARM.Build.0 = Debug|ARM 20 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|Win32.Build.0 = Debug|Win32 22 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|x64.ActiveCfg = Debug|x64 23 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Debug|x64.Build.0 = Debug|x64 24 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|ARM.ActiveCfg = Release|ARM 25 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|ARM.Build.0 = Release|ARM 26 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|Win32.ActiveCfg = Release|Win32 27 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|Win32.Build.0 = Release|Win32 28 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|x64.ActiveCfg = Release|x64 29 | {7DEA2454-385C-414C-8965-5D11DD9195D7}.Release|x64.Build.0 = Release|x64 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /Strings2Managed/Strings2Managed.v12.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavelinNetworks/IR-Tools/1e82e9592a3f5893ba39965f5d44404ddf43e697/Strings2Managed/Strings2Managed.v12.suo -------------------------------------------------------------------------------- /Strings2Managed/Strings2Managed.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {7DEA2454-385C-414C-8965-5D11DD9195D7} 31 | v3.5 32 | ManagedCProj 33 | Strings2Managed 34 | Strings2Managed 35 | 36 | 37 | 38 | DynamicLibrary 39 | true 40 | v90 41 | Pure 42 | Unicode 43 | 44 | 45 | DynamicLibrary 46 | true 47 | v120 48 | true 49 | Unicode 50 | 51 | 52 | DynamicLibrary 53 | true 54 | v90 55 | Pure 56 | Unicode 57 | 58 | 59 | DynamicLibrary 60 | false 61 | v90 62 | Pure 63 | Unicode 64 | 65 | 66 | DynamicLibrary 67 | false 68 | v90 69 | Pure 70 | Unicode 71 | 72 | 73 | DynamicLibrary 74 | false 75 | v90 76 | Pure 77 | Unicode 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | true 103 | 104 | 105 | true 106 | 107 | 108 | true 109 | 110 | 111 | false 112 | 113 | 114 | false 115 | 116 | 117 | false 118 | 119 | 120 | 121 | Level3 122 | Disabled 123 | WIN32;_DEBUG;%(PreprocessorDefinitions) 124 | Use 125 | 126 | 127 | true 128 | Advapi32.lib; 129 | MachineX86 130 | 131 | 132 | 133 | 134 | Level3 135 | Disabled 136 | WIN32;_DEBUG;%(PreprocessorDefinitions) 137 | Use 138 | 139 | 140 | true 141 | 142 | 143 | 144 | 145 | 146 | 147 | Level3 148 | Disabled 149 | WIN32;_DEBUG;%(PreprocessorDefinitions) 150 | Use 151 | 152 | 153 | true 154 | Advapi32.lib; 155 | MachineX64 156 | 157 | 158 | 159 | 160 | Level3 161 | WIN32;NDEBUG;%(PreprocessorDefinitions) 162 | Use 163 | Advapi32.dll; 164 | 165 | 166 | true 167 | Advapi32.lib; 168 | 169 | 170 | 171 | 172 | Level3 173 | WIN32;NDEBUG;%(PreprocessorDefinitions) 174 | Use 175 | Advapi32.dll; 176 | 177 | 178 | true 179 | Advapi32.lib; 180 | 181 | 182 | 183 | 184 | Level3 185 | WIN32;NDEBUG;%(PreprocessorDefinitions) 186 | Use 187 | Advapi32.dll; 188 | 189 | 190 | true 191 | Advapi32.lib; 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | Create 223 | Create 224 | Create 225 | Create 226 | Create 227 | Create 228 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /Strings2Managed/Strings2Managed.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | Header Files 41 | 42 | 43 | Header Files 44 | 45 | 46 | Header Files 47 | 48 | 49 | Header Files 50 | 51 | 52 | Header Files 53 | 54 | 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | Source Files 73 | 74 | 75 | Source Files 76 | 77 | 78 | Source Files 79 | 80 | 81 | Source Files 82 | 83 | 84 | -------------------------------------------------------------------------------- /Strings2Managed/Strings2Managed.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /Strings2Managed/Strings2ManagedWrapper.cpp: -------------------------------------------------------------------------------- 1 | // This is the main DLL file. 2 | 3 | #include , 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "stdafx.h" 10 | #include "strings2.h" 11 | #include "Strings2ManagedWrapper.h" 12 | using namespace System; 13 | using namespace msclr::interop; 14 | using namespace System::Collections; 15 | 16 | 17 | 18 | namespace Strings2Managed { 19 | 20 | List^ Strings2ManagedWrapper::FileToStrings(String^ filePath) 21 | { 22 | wstring x = msclr::interop::marshal_as(filePath); 23 | WCHAR path[MAX_LENGTH] = { 0 }; 24 | swprintf_s(path, L"%ls", x.c_str()); 25 | WCHAR** infoArgs = (WCHAR**)malloc(INFO_ARGS * sizeof(WCHAR*)); 26 | infoArgs[0] = L""; 27 | infoArgs[1] = L"-file"; 28 | infoArgs[2] = path; 29 | List^ res = gcnew List(); 30 | 31 | mainFunction(infoArgs, INFO_ARGS, res); 32 | 33 | return res; 34 | } 35 | 36 | List^ Strings2ManagedWrapper::ProcessToStrings(int processID) 37 | { 38 | WCHAR path[MAX_LENGTH] = { 0 }; 39 | swprintf_s(path, L"%d", processID); 40 | WCHAR** infoArgs = (WCHAR**)malloc(INFO_ARGS * sizeof(WCHAR*)); 41 | infoArgs[0] = L""; 42 | infoArgs[1] = L"-pid"; 43 | infoArgs[2] = path; 44 | List^ res = gcnew List(); 45 | 46 | mainFunction(infoArgs, INFO_ARGS, res); 47 | 48 | return res; 49 | } 50 | } -------------------------------------------------------------------------------- /Strings2Managed/Strings2ManagedWrapper.h: -------------------------------------------------------------------------------- 1 | // ADEvents.h 2 | 3 | #pragma once 4 | 5 | #include "stdafx.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #pragma comment(lib, "credui.lib") 18 | #pragma comment(lib, "wecapi.lib") 19 | 20 | using namespace std; 21 | using namespace System; 22 | using namespace System::Collections::Generic; 23 | using namespace System::Diagnostics; 24 | using namespace System::Text; 25 | using namespace System::IO; 26 | using namespace System::Text::RegularExpressions; 27 | 28 | namespace Strings2Managed { 29 | 30 | public ref class Strings2ManagedWrapper 31 | { 32 | public: 33 | List^ FileToStrings(String^ path); 34 | List^ ProcessToStrings(int processID); 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /Strings2Managed/basics.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "basics.h" 3 | 4 | void PrintLastError(LPTSTR lpszFunction) 5 | { 6 | // Retrieve the system error message for the last-error code 7 | // LPVOID lpMsgBuf; 8 | // LPVOID lpDisplayBuf; 9 | // DWORD dw = GetLastError(); 10 | 11 | // FormatMessage( 12 | // FORMAT_MESSAGE_ALLOCATE_BUFFER | 13 | // FORMAT_MESSAGE_FROM_SYSTEM | 14 | // FORMAT_MESSAGE_IGNORE_INSERTS, 15 | // NULL, 16 | // dw, 17 | // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 18 | // (LPTSTR) &lpMsgBuf, 19 | // 0, NULL ); 20 | 21 | // // Display the error message and exit the process 22 | // //lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 23 | // // (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); 24 | // //StringCchPrintf((LPTSTR)lpDisplayBuf, 25 | // // LocalSize(lpDisplayBuf) / sizeof(TCHAR), 26 | // // TEXT("%s failed with error %d: %s"), 27 | // // lpszFunction, dw, lpMsgBuf); 28 | 29 | ////fwprintf(stderr,(LPCTSTR) lpDisplayBuf ); 30 | 31 | // LocalFree(lpMsgBuf); 32 | // LocalFree(lpDisplayBuf); 33 | } -------------------------------------------------------------------------------- /Strings2Managed/basics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | void PrintLastError(LPTSTR lpszFunction); -------------------------------------------------------------------------------- /Strings2Managed/dirent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * Dirent interface for Microsoft Visual Studio 5 | * Version 1.21 6 | * 7 | * Copyright (C) 2006-2012 Toni Ronkko 8 | * This file is part of dirent. Dirent may be freely distributed 9 | * under the MIT license. For all details and documentation, see 10 | * https://github.com/tronkko/dirent 11 | */ 12 | #ifndef DIRENT_H 13 | #define DIRENT_H 14 | 15 | /* 16 | * Include windows.h without Windows Sockets 1.1 to prevent conflicts with 17 | * Windows Sockets 2.0. 18 | */ 19 | #ifndef WIN32_LEAN_AND_MEAN 20 | # define WIN32_LEAN_AND_MEAN 21 | #endif 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | /* Indicates that d_type field is available in dirent structure */ 35 | #define _DIRENT_HAVE_D_TYPE 36 | 37 | /* Indicates that d_namlen field is available in dirent structure */ 38 | #define _DIRENT_HAVE_D_NAMLEN 39 | 40 | /* Entries missing from MSVC 6.0 */ 41 | #if !defined(FILE_ATTRIBUTE_DEVICE) 42 | # define FILE_ATTRIBUTE_DEVICE 0x40 43 | #endif 44 | 45 | /* File type and permission flags for stat(), general mask */ 46 | #if !defined(S_IFMT) 47 | # define S_IFMT _S_IFMT 48 | #endif 49 | 50 | /* Directory bit */ 51 | #if !defined(S_IFDIR) 52 | # define S_IFDIR _S_IFDIR 53 | #endif 54 | 55 | /* Character device bit */ 56 | #if !defined(S_IFCHR) 57 | # define S_IFCHR _S_IFCHR 58 | #endif 59 | 60 | /* Pipe bit */ 61 | #if !defined(S_IFFIFO) 62 | # define S_IFFIFO _S_IFFIFO 63 | #endif 64 | 65 | /* Regular file bit */ 66 | #if !defined(S_IFREG) 67 | # define S_IFREG _S_IFREG 68 | #endif 69 | 70 | /* Read permission */ 71 | #if !defined(S_IREAD) 72 | # define S_IREAD _S_IREAD 73 | #endif 74 | 75 | /* Write permission */ 76 | #if !defined(S_IWRITE) 77 | # define S_IWRITE _S_IWRITE 78 | #endif 79 | 80 | /* Execute permission */ 81 | #if !defined(S_IEXEC) 82 | # define S_IEXEC _S_IEXEC 83 | #endif 84 | 85 | /* Pipe */ 86 | #if !defined(S_IFIFO) 87 | # define S_IFIFO _S_IFIFO 88 | #endif 89 | 90 | /* Block device */ 91 | #if !defined(S_IFBLK) 92 | # define S_IFBLK 0 93 | #endif 94 | 95 | /* Link */ 96 | #if !defined(S_IFLNK) 97 | # define S_IFLNK 0 98 | #endif 99 | 100 | /* Socket */ 101 | #if !defined(S_IFSOCK) 102 | # define S_IFSOCK 0 103 | #endif 104 | 105 | /* Read user permission */ 106 | #if !defined(S_IRUSR) 107 | # define S_IRUSR S_IREAD 108 | #endif 109 | 110 | /* Write user permission */ 111 | #if !defined(S_IWUSR) 112 | # define S_IWUSR S_IWRITE 113 | #endif 114 | 115 | /* Execute user permission */ 116 | #if !defined(S_IXUSR) 117 | # define S_IXUSR 0 118 | #endif 119 | 120 | /* Read group permission */ 121 | #if !defined(S_IRGRP) 122 | # define S_IRGRP 0 123 | #endif 124 | 125 | /* Write group permission */ 126 | #if !defined(S_IWGRP) 127 | # define S_IWGRP 0 128 | #endif 129 | 130 | /* Execute group permission */ 131 | #if !defined(S_IXGRP) 132 | # define S_IXGRP 0 133 | #endif 134 | 135 | /* Read others permission */ 136 | #if !defined(S_IROTH) 137 | # define S_IROTH 0 138 | #endif 139 | 140 | /* Write others permission */ 141 | #if !defined(S_IWOTH) 142 | # define S_IWOTH 0 143 | #endif 144 | 145 | /* Execute others permission */ 146 | #if !defined(S_IXOTH) 147 | # define S_IXOTH 0 148 | #endif 149 | 150 | /* Maximum length of file name */ 151 | #if !defined(PATH_MAX) 152 | # define PATH_MAX MAX_PATH 153 | #endif 154 | #if !defined(FILENAME_MAX) 155 | # define FILENAME_MAX MAX_PATH 156 | #endif 157 | #if !defined(NAME_MAX) 158 | # define NAME_MAX FILENAME_MAX 159 | #endif 160 | 161 | /* File type flags for d_type */ 162 | #define DT_UNKNOWN 0 163 | #define DT_REG S_IFREG 164 | #define DT_DIR S_IFDIR 165 | #define DT_FIFO S_IFIFO 166 | #define DT_SOCK S_IFSOCK 167 | #define DT_CHR S_IFCHR 168 | #define DT_BLK S_IFBLK 169 | #define DT_LNK S_IFLNK 170 | 171 | /* Macros for converting between st_mode and d_type */ 172 | #define IFTODT(mode) ((mode) & S_IFMT) 173 | #define DTTOIF(type) (type) 174 | 175 | /* 176 | * File type macros. Note that block devices, sockets and links cannot be 177 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are 178 | * only defined for compatibility. These macros should always return false 179 | * on Windows. 180 | */ 181 | #if !defined(S_ISFIFO) 182 | # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 183 | #endif 184 | #if !defined(S_ISDIR) 185 | # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 186 | #endif 187 | #if !defined(S_ISREG) 188 | # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 189 | #endif 190 | #if !defined(S_ISLNK) 191 | # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 192 | #endif 193 | #if !defined(S_ISSOCK) 194 | # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 195 | #endif 196 | #if !defined(S_ISCHR) 197 | # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 198 | #endif 199 | #if !defined(S_ISBLK) 200 | # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 201 | #endif 202 | 203 | /* Return the exact length of d_namlen without zero terminator */ 204 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 205 | 206 | /* Return number of bytes needed to store d_namlen */ 207 | #define _D_ALLOC_NAMLEN(p) (PATH_MAX) 208 | 209 | 210 | #ifdef __cplusplus 211 | extern "C" { 212 | #endif 213 | 214 | 215 | /* Wide-character version */ 216 | struct _wdirent { 217 | /* Always zero */ 218 | long d_ino; 219 | 220 | /* Structure size */ 221 | unsigned short d_reclen; 222 | 223 | /* Length of name without \0 */ 224 | size_t d_namlen; 225 | 226 | /* File type */ 227 | int d_type; 228 | 229 | /* File name */ 230 | wchar_t d_name[PATH_MAX]; 231 | }; 232 | typedef struct _wdirent _wdirent; 233 | 234 | struct _WDIR { 235 | /* Current directory entry */ 236 | struct _wdirent ent; 237 | 238 | /* Private file data */ 239 | WIN32_FIND_DATAW data; 240 | 241 | /* True if data is valid */ 242 | int cached; 243 | 244 | /* Win32 search handle */ 245 | HANDLE handle; 246 | 247 | /* Initial directory name */ 248 | wchar_t *patt; 249 | }; 250 | typedef struct _WDIR _WDIR; 251 | 252 | static _WDIR *_wopendir(const wchar_t *dirname); 253 | static struct _wdirent *_wreaddir(_WDIR *dirp); 254 | static int _wclosedir(_WDIR *dirp); 255 | static void _wrewinddir(_WDIR* dirp); 256 | 257 | 258 | /* For compatibility with Symbian */ 259 | #define wdirent _wdirent 260 | #define WDIR _WDIR 261 | #define wopendir _wopendir 262 | #define wreaddir _wreaddir 263 | #define wclosedir _wclosedir 264 | #define wrewinddir _wrewinddir 265 | 266 | 267 | /* Multi-byte character versions */ 268 | struct dirent { 269 | /* Always zero */ 270 | long d_ino; 271 | 272 | /* Structure size */ 273 | unsigned short d_reclen; 274 | 275 | /* Length of name without \0 */ 276 | size_t d_namlen; 277 | 278 | /* File type */ 279 | int d_type; 280 | 281 | /* File name */ 282 | char d_name[PATH_MAX]; 283 | }; 284 | typedef struct dirent dirent; 285 | 286 | struct DIR { 287 | struct dirent ent; 288 | struct _WDIR *wdirp; 289 | }; 290 | typedef struct DIR DIR; 291 | 292 | static DIR *opendir(const char *dirname); 293 | static struct dirent *readdir(DIR *dirp); 294 | static int closedir(DIR *dirp); 295 | static void rewinddir(DIR* dirp); 296 | 297 | 298 | /* Internal utility functions */ 299 | static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp); 300 | static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp); 301 | 302 | static int dirent_mbstowcs_s( 303 | size_t *pReturnValue, 304 | wchar_t *wcstr, 305 | size_t sizeInWords, 306 | const char *mbstr, 307 | size_t count); 308 | 309 | static int dirent_wcstombs_s( 310 | size_t *pReturnValue, 311 | char *mbstr, 312 | size_t sizeInBytes, 313 | const wchar_t *wcstr, 314 | size_t count); 315 | 316 | static void dirent_set_errno(int error); 317 | 318 | /* 319 | * Open directory stream DIRNAME for read and return a pointer to the 320 | * internal working area that is used to retrieve individual directory 321 | * entries. 322 | */ 323 | static _WDIR* 324 | _wopendir( 325 | const wchar_t *dirname) 326 | { 327 | _WDIR *dirp = NULL; 328 | int error; 329 | 330 | /* Must have directory name */ 331 | if (dirname == NULL || dirname[0] == '\0') { 332 | dirent_set_errno(ENOENT); 333 | return NULL; 334 | } 335 | 336 | /* Allocate new _WDIR structure */ 337 | dirp = (_WDIR*)malloc(sizeof(struct _WDIR)); 338 | if (dirp != NULL) { 339 | DWORD n; 340 | 341 | /* Reset _WDIR structure */ 342 | dirp->handle = INVALID_HANDLE_VALUE; 343 | dirp->patt = NULL; 344 | dirp->cached = 0; 345 | 346 | /* Compute the length of full path plus zero terminator 347 | * 348 | * Note that on WinRT there's no way to convert relative paths 349 | * into absolute paths, so just assume its an absolute path. 350 | */ 351 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) 352 | n = wcslen(dirname); 353 | # else 354 | n = GetFullPathNameW(dirname, 0, NULL, NULL); 355 | # endif 356 | 357 | /* Allocate room for absolute directory name and search pattern */ 358 | dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16); 359 | if (dirp->patt) { 360 | 361 | /* 362 | * Convert relative directory name to an absolute one. This 363 | * allows rewinddir() to function correctly even when current 364 | * working directory is changed between opendir() and rewinddir(). 365 | * 366 | * Note that on WinRT there's no way to convert relative paths 367 | * into absolute paths, so just assume its an absolute path. 368 | */ 369 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) 370 | wcsncpy_s(dirp->patt, n + 1, dirname, n); 371 | # else 372 | n = GetFullPathNameW(dirname, n, dirp->patt, NULL); 373 | # endif 374 | if (n > 0) { 375 | wchar_t *p; 376 | 377 | /* Append search pattern \* to the directory name */ 378 | p = dirp->patt + n; 379 | if (dirp->patt < p) { 380 | switch (p[-1]) { 381 | case '\\': 382 | case '/': 383 | case ':': 384 | /* Directory ends in path separator, e.g. c:\temp\ */ 385 | /*NOP*/; 386 | break; 387 | 388 | default: 389 | /* Directory name doesn't end in path separator */ 390 | *p++ = '\\'; 391 | } 392 | } 393 | *p++ = '*'; 394 | *p = '\0'; 395 | 396 | /* Open directory stream and retrieve the first entry */ 397 | if (dirent_first(dirp)) { 398 | /* Directory stream opened successfully */ 399 | error = 0; 400 | } 401 | else { 402 | /* Cannot retrieve first entry */ 403 | error = 1; 404 | dirent_set_errno(ENOENT); 405 | } 406 | 407 | } 408 | else { 409 | /* Cannot retrieve full path name */ 410 | dirent_set_errno(ENOENT); 411 | error = 1; 412 | } 413 | 414 | } 415 | else { 416 | /* Cannot allocate memory for search pattern */ 417 | error = 1; 418 | } 419 | 420 | } 421 | else { 422 | /* Cannot allocate _WDIR structure */ 423 | error = 1; 424 | } 425 | 426 | /* Clean up in case of error */ 427 | if (error && dirp) { 428 | _wclosedir(dirp); 429 | dirp = NULL; 430 | } 431 | 432 | return dirp; 433 | } 434 | 435 | /* 436 | * Read next directory entry. The directory entry is returned in dirent 437 | * structure in the d_name field. Individual directory entries returned by 438 | * this function include regular files, sub-directories, pseudo-directories 439 | * "." and ".." as well as volume labels, hidden files and system files. 440 | */ 441 | static struct _wdirent* 442 | _wreaddir( 443 | _WDIR *dirp) 444 | { 445 | WIN32_FIND_DATAW *datap; 446 | struct _wdirent *entp; 447 | 448 | /* Read next directory entry */ 449 | datap = dirent_next(dirp); 450 | if (datap) { 451 | size_t n; 452 | DWORD attr; 453 | 454 | /* Pointer to directory entry to return */ 455 | entp = &dirp->ent; 456 | 457 | /* 458 | * Copy file name as wide-character string. If the file name is too 459 | * long to fit in to the destination buffer, then truncate file name 460 | * to PATH_MAX characters and zero-terminate the buffer. 461 | */ 462 | n = 0; 463 | while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { 464 | entp->d_name[n] = datap->cFileName[n]; 465 | n++; 466 | } 467 | dirp->ent.d_name[n] = 0; 468 | 469 | /* Length of file name excluding zero terminator */ 470 | entp->d_namlen = n; 471 | 472 | /* File type */ 473 | attr = datap->dwFileAttributes; 474 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 475 | entp->d_type = DT_CHR; 476 | } 477 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 478 | entp->d_type = DT_DIR; 479 | } 480 | else { 481 | entp->d_type = DT_REG; 482 | } 483 | 484 | /* Reset dummy fields */ 485 | entp->d_ino = 0; 486 | entp->d_reclen = sizeof(struct _wdirent); 487 | 488 | } 489 | else { 490 | 491 | /* Last directory entry read */ 492 | entp = NULL; 493 | 494 | } 495 | 496 | return entp; 497 | } 498 | 499 | /* 500 | * Close directory stream opened by opendir() function. This invalidates the 501 | * DIR structure as well as any directory entry read previously by 502 | * _wreaddir(). 503 | */ 504 | static int 505 | _wclosedir( 506 | _WDIR *dirp) 507 | { 508 | int ok; 509 | if (dirp) { 510 | 511 | /* Release search handle */ 512 | if (dirp->handle != INVALID_HANDLE_VALUE) { 513 | FindClose(dirp->handle); 514 | dirp->handle = INVALID_HANDLE_VALUE; 515 | } 516 | 517 | /* Release search pattern */ 518 | if (dirp->patt) { 519 | free(dirp->patt); 520 | dirp->patt = NULL; 521 | } 522 | 523 | /* Release directory structure */ 524 | free(dirp); 525 | ok = /*success*/0; 526 | 527 | } 528 | else { 529 | /* Invalid directory stream */ 530 | dirent_set_errno(EBADF); 531 | ok = /*failure*/-1; 532 | } 533 | return ok; 534 | } 535 | 536 | /* 537 | * Rewind directory stream such that _wreaddir() returns the very first 538 | * file name again. 539 | */ 540 | static void 541 | _wrewinddir( 542 | _WDIR* dirp) 543 | { 544 | if (dirp) { 545 | /* Release existing search handle */ 546 | if (dirp->handle != INVALID_HANDLE_VALUE) { 547 | FindClose(dirp->handle); 548 | } 549 | 550 | /* Open new search handle */ 551 | dirent_first(dirp); 552 | } 553 | } 554 | 555 | /* Get first directory entry (internal) */ 556 | static WIN32_FIND_DATAW* 557 | dirent_first( 558 | _WDIR *dirp) 559 | { 560 | WIN32_FIND_DATAW *datap; 561 | 562 | /* Open directory and retrieve the first entry */ 563 | dirp->handle = FindFirstFileExW( 564 | dirp->patt, FindExInfoStandard, &dirp->data, 565 | FindExSearchNameMatch, NULL, 0); 566 | if (dirp->handle != INVALID_HANDLE_VALUE) { 567 | 568 | /* a directory entry is now waiting in memory */ 569 | datap = &dirp->data; 570 | dirp->cached = 1; 571 | 572 | } 573 | else { 574 | 575 | /* Failed to re-open directory: no directory entry in memory */ 576 | dirp->cached = 0; 577 | datap = NULL; 578 | 579 | } 580 | return datap; 581 | } 582 | 583 | /* Get next directory entry (internal) */ 584 | static WIN32_FIND_DATAW* 585 | dirent_next( 586 | _WDIR *dirp) 587 | { 588 | WIN32_FIND_DATAW *p; 589 | 590 | /* Get next directory entry */ 591 | if (dirp->cached != 0) { 592 | 593 | /* A valid directory entry already in memory */ 594 | p = &dirp->data; 595 | dirp->cached = 0; 596 | 597 | } 598 | else if (dirp->handle != INVALID_HANDLE_VALUE) { 599 | 600 | /* Get the next directory entry from stream */ 601 | if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) { 602 | /* Got a file */ 603 | p = &dirp->data; 604 | } 605 | else { 606 | /* The very last entry has been processed or an error occured */ 607 | FindClose(dirp->handle); 608 | dirp->handle = INVALID_HANDLE_VALUE; 609 | p = NULL; 610 | } 611 | 612 | } 613 | else { 614 | 615 | /* End of directory stream reached */ 616 | p = NULL; 617 | 618 | } 619 | 620 | return p; 621 | } 622 | 623 | /* 624 | * Open directory stream using plain old C-string. 625 | */ 626 | static DIR* 627 | opendir( 628 | const char *dirname) 629 | { 630 | struct DIR *dirp; 631 | int error; 632 | 633 | /* Must have directory name */ 634 | if (dirname == NULL || dirname[0] == '\0') { 635 | dirent_set_errno(ENOENT); 636 | return NULL; 637 | } 638 | 639 | /* Allocate memory for DIR structure */ 640 | dirp = (DIR*)malloc(sizeof(struct DIR)); 641 | if (dirp) { 642 | wchar_t wname[PATH_MAX]; 643 | size_t n; 644 | 645 | /* Convert directory name to wide-character string */ 646 | error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX); 647 | if (!error) { 648 | 649 | /* Open directory stream using wide-character name */ 650 | dirp->wdirp = _wopendir(wname); 651 | if (dirp->wdirp) { 652 | /* Directory stream opened */ 653 | error = 0; 654 | } 655 | else { 656 | /* Failed to open directory stream */ 657 | error = 1; 658 | } 659 | 660 | } 661 | else { 662 | /* 663 | * Cannot convert file name to wide-character string. This 664 | * occurs if the string contains invalid multi-byte sequences or 665 | * the output buffer is too small to contain the resulting 666 | * string. 667 | */ 668 | error = 1; 669 | } 670 | 671 | } 672 | else { 673 | /* Cannot allocate DIR structure */ 674 | error = 1; 675 | } 676 | 677 | /* Clean up in case of error */ 678 | if (error && dirp) { 679 | free(dirp); 680 | dirp = NULL; 681 | } 682 | 683 | return dirp; 684 | } 685 | 686 | /* 687 | * Read next directory entry. 688 | * 689 | * When working with text consoles, please note that file names returned by 690 | * readdir() are represented in the default ANSI code page while any output to 691 | * console is typically formatted on another code page. Thus, non-ASCII 692 | * characters in file names will not usually display correctly on console. The 693 | * problem can be fixed in two ways: (1) change the character set of console 694 | * to 1252 using chcp utility and use Lucida Console font, or (2) use 695 | * _cprintf function when writing to console. The _cprinf() will re-encode 696 | * ANSI strings to the console code page so many non-ASCII characters will 697 | * display correcly. 698 | */ 699 | static struct dirent* 700 | readdir( 701 | DIR *dirp) 702 | { 703 | WIN32_FIND_DATAW *datap; 704 | struct dirent *entp; 705 | 706 | /* Read next directory entry */ 707 | datap = dirent_next(dirp->wdirp); 708 | if (datap) { 709 | size_t n; 710 | int error; 711 | 712 | /* Attempt to convert file name to multi-byte string */ 713 | error = dirent_wcstombs_s( 714 | &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); 715 | 716 | /* 717 | * If the file name cannot be represented by a multi-byte string, 718 | * then attempt to use old 8+3 file name. This allows traditional 719 | * Unix-code to access some file names despite of unicode 720 | * characters, although file names may seem unfamiliar to the user. 721 | * 722 | * Be ware that the code below cannot come up with a short file 723 | * name unless the file system provides one. At least 724 | * VirtualBox shared folders fail to do this. 725 | */ 726 | if (error && datap->cAlternateFileName[0] != '\0') { 727 | error = dirent_wcstombs_s( 728 | &n, dirp->ent.d_name, PATH_MAX, 729 | datap->cAlternateFileName, PATH_MAX); 730 | } 731 | 732 | if (!error) { 733 | DWORD attr; 734 | 735 | /* Initialize directory entry for return */ 736 | entp = &dirp->ent; 737 | 738 | /* Length of file name excluding zero terminator */ 739 | entp->d_namlen = n - 1; 740 | 741 | /* File attributes */ 742 | attr = datap->dwFileAttributes; 743 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { 744 | entp->d_type = DT_CHR; 745 | } 746 | else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { 747 | entp->d_type = DT_DIR; 748 | } 749 | else { 750 | entp->d_type = DT_REG; 751 | } 752 | 753 | /* Reset dummy fields */ 754 | entp->d_ino = 0; 755 | entp->d_reclen = sizeof(struct dirent); 756 | 757 | } 758 | else { 759 | /* 760 | * Cannot convert file name to multi-byte string so construct 761 | * an errornous directory entry and return that. Note that 762 | * we cannot return NULL as that would stop the processing 763 | * of directory entries completely. 764 | */ 765 | entp = &dirp->ent; 766 | entp->d_name[0] = '?'; 767 | entp->d_name[1] = '\0'; 768 | entp->d_namlen = 1; 769 | entp->d_type = DT_UNKNOWN; 770 | entp->d_ino = 0; 771 | entp->d_reclen = 0; 772 | } 773 | 774 | } 775 | else { 776 | /* No more directory entries */ 777 | entp = NULL; 778 | } 779 | 780 | return entp; 781 | } 782 | 783 | /* 784 | * Close directory stream. 785 | */ 786 | static int 787 | closedir( 788 | DIR *dirp) 789 | { 790 | int ok; 791 | if (dirp) { 792 | 793 | /* Close wide-character directory stream */ 794 | ok = _wclosedir(dirp->wdirp); 795 | dirp->wdirp = NULL; 796 | 797 | /* Release multi-byte character version */ 798 | free(dirp); 799 | 800 | } 801 | else { 802 | 803 | /* Invalid directory stream */ 804 | dirent_set_errno(EBADF); 805 | ok = /*failure*/-1; 806 | 807 | } 808 | return ok; 809 | } 810 | 811 | /* 812 | * Rewind directory stream to beginning. 813 | */ 814 | static void 815 | rewinddir( 816 | DIR* dirp) 817 | { 818 | /* Rewind wide-character string directory stream */ 819 | _wrewinddir(dirp->wdirp); 820 | } 821 | 822 | /* Convert multi-byte string to wide character string */ 823 | static int 824 | dirent_mbstowcs_s( 825 | size_t *pReturnValue, 826 | wchar_t *wcstr, 827 | size_t sizeInWords, 828 | const char *mbstr, 829 | size_t count) 830 | { 831 | int error; 832 | 833 | #if defined(_MSC_VER) && _MSC_VER >= 1400 834 | 835 | /* Microsoft Visual Studio 2005 or later */ 836 | error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count); 837 | 838 | #else 839 | 840 | /* Older Visual Studio or non-Microsoft compiler */ 841 | size_t n; 842 | 843 | /* Convert to wide-character string (or count characters) */ 844 | n = mbstowcs(wcstr, mbstr, sizeInWords); 845 | if (!wcstr || n < count) { 846 | 847 | /* Zero-terminate output buffer */ 848 | if (wcstr && sizeInWords) { 849 | if (n >= sizeInWords) { 850 | n = sizeInWords - 1; 851 | } 852 | wcstr[n] = 0; 853 | } 854 | 855 | /* Length of resuting multi-byte string WITH zero terminator */ 856 | if (pReturnValue) { 857 | *pReturnValue = n + 1; 858 | } 859 | 860 | /* Success */ 861 | error = 0; 862 | 863 | } 864 | else { 865 | 866 | /* Could not convert string */ 867 | error = 1; 868 | 869 | } 870 | 871 | #endif 872 | 873 | return error; 874 | } 875 | 876 | /* Convert wide-character string to multi-byte string */ 877 | static int 878 | dirent_wcstombs_s( 879 | size_t *pReturnValue, 880 | char *mbstr, 881 | size_t sizeInBytes, /* max size of mbstr */ 882 | const wchar_t *wcstr, 883 | size_t count) 884 | { 885 | int error; 886 | 887 | #if defined(_MSC_VER) && _MSC_VER >= 1400 888 | 889 | /* Microsoft Visual Studio 2005 or later */ 890 | error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count); 891 | 892 | #else 893 | 894 | /* Older Visual Studio or non-Microsoft compiler */ 895 | size_t n; 896 | 897 | /* Convert to multi-byte string (or count the number of bytes needed) */ 898 | n = wcstombs(mbstr, wcstr, sizeInBytes); 899 | if (!mbstr || n < count) { 900 | 901 | /* Zero-terminate output buffer */ 902 | if (mbstr && sizeInBytes) { 903 | if (n >= sizeInBytes) { 904 | n = sizeInBytes - 1; 905 | } 906 | mbstr[n] = '\0'; 907 | } 908 | 909 | /* Length of resulting multi-bytes string WITH zero-terminator */ 910 | if (pReturnValue) { 911 | *pReturnValue = n + 1; 912 | } 913 | 914 | /* Success */ 915 | error = 0; 916 | 917 | } 918 | else { 919 | 920 | /* Cannot convert string */ 921 | error = 1; 922 | 923 | } 924 | 925 | #endif 926 | 927 | return error; 928 | } 929 | 930 | /* Set errno variable */ 931 | static void 932 | dirent_set_errno( 933 | int error) 934 | { 935 | #if defined(_MSC_VER) && _MSC_VER >= 1400 936 | 937 | /* Microsoft Visual Studio 2005 and later */ 938 | _set_errno(error); 939 | 940 | #else 941 | 942 | /* Non-Microsoft compiler or older Microsoft compiler */ 943 | errno = error; 944 | 945 | #endif 946 | } 947 | 948 | 949 | #ifdef __cplusplus 950 | } 951 | #endif 952 | #endif /*DIRENT_H*/ 953 | -------------------------------------------------------------------------------- /Strings2Managed/module.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "module.h" 3 | 4 | bool module::contains(unsigned int address) 5 | { 6 | // Check if this module contains the specified address 7 | return (byte*) address >= moduleDetails.modBaseAddr && (byte*) address < moduleDetails.modBaseAddr + moduleDetails.modBaseSize; 8 | } 9 | 10 | bool module::operator== (const module &other) const 11 | { 12 | return this->moduleDetails.hModule == other.moduleDetails.hModule; 13 | } 14 | 15 | module::module(MODULEENTRY32W details) 16 | { 17 | moduleDetails = details; 18 | } 19 | 20 | module::~module(void) 21 | { 22 | } 23 | -------------------------------------------------------------------------------- /Strings2Managed/module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "DynArray.h" 7 | 8 | class module 9 | { 10 | MODULEENTRY32W moduleDetails; 11 | public: 12 | bool contains(unsigned int address); 13 | 14 | module(MODULEENTRY32W details); 15 | ~module(void); 16 | bool operator== (const module &other) const; 17 | }; 18 | -------------------------------------------------------------------------------- /Strings2Managed/print_buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "print_buffer.h" 3 | 4 | print_buffer::print_buffer(int buffer_size) 5 | { 6 | this->buffer_size = buffer_size; 7 | this->buffer = new char[buffer_size]; 8 | this->space_used = 0; 9 | } 10 | 11 | void print_buffer::addString(char* string, int length) 12 | { 13 | // Digest the buffer if it is full 14 | if( space_used + length + 1 >= buffer_size ) 15 | digest(); 16 | 17 | // Copy the string if there is room 18 | if( space_used + length + 1 >= buffer_size ) 19 | { 20 | // Digest this string without buffering it 21 | fwrite(string, length, 1, stdout); 22 | }else{ 23 | // Add it to the buffer 24 | memcpy( buffer + space_used, string, length ); 25 | space_used += length; 26 | buffer[space_used] = 0; 27 | } 28 | } 29 | 30 | void print_buffer::addString(char* string) 31 | { 32 | int length = strlen(string); 33 | addString(string, length); 34 | } 35 | 36 | void print_buffer::addStrings(char* string1, char* string2, char* string3, char* string4, char* string5) 37 | { 38 | addString(string1); 39 | addString(string2); 40 | addString(string3); 41 | addString(string4); 42 | addString(string5); 43 | } 44 | 45 | void print_buffer::addStrings(char* string1, char* string2, char* string3, char* string4) 46 | { 47 | addString(string1); 48 | addString(string2); 49 | addString(string3); 50 | addString(string4); 51 | } 52 | 53 | void print_buffer::addStrings(char* string1, char* string2, char* string3) 54 | { 55 | addString(string1); 56 | addString(string2); 57 | addString(string3); 58 | } 59 | 60 | void print_buffer::addStrings(char* string1, char* string2) 61 | { 62 | addString(string1); 63 | addString(string2); 64 | } 65 | 66 | void print_buffer::addLine(char* string, int length) 67 | { 68 | // Digest the buffer if it is full 69 | if( space_used + length + 3 >= buffer_size ) 70 | digest(); 71 | 72 | // Copy the string if there is room 73 | if( space_used + length + 3 >= buffer_size ) 74 | { 75 | // Digest this string without buffering it 76 | printf( "%s", string ); 77 | }else{ 78 | // Add it to the buffer 79 | memcpy( buffer + space_used, string, length ); 80 | space_used += length + 2; 81 | buffer[space_used - 2] = '\r'; 82 | buffer[space_used - 1] = '\n'; 83 | buffer[space_used] = 0; 84 | } 85 | } 86 | 87 | void print_buffer::addLine(char* string) 88 | { 89 | int length = strlen(string); 90 | addLine(string, length); 91 | } 92 | 93 | void print_buffer::digest() 94 | { 95 | if( space_used > 0 ) 96 | { 97 | // Print the current buffer 98 | fwrite( buffer, 1, space_used, stdout); 99 | fflush( stdout ); 100 | buffer[0] = 0; 101 | space_used = 0; 102 | } 103 | } 104 | 105 | print_buffer::~print_buffer(void) 106 | { 107 | digest(); 108 | delete[] buffer; 109 | } 110 | -------------------------------------------------------------------------------- /Strings2Managed/print_buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class print_buffer 7 | { 8 | int buffer_size; 9 | int space_used; 10 | char* buffer; 11 | public: 12 | void addStrings(char* string1, char* string2, char* string3, char* string4, char* string5); 13 | void addStrings(char* string1, char* string2, char* string3, char* string4); 14 | void addStrings(char* string1, char* string2, char* string3); 15 | void addStrings(char* string1, char* string2); 16 | void addString(char* string, int length); 17 | void addString(char* string); 18 | void addLine(char* string, int length); 19 | void addLine(char* string); 20 | void digest(); 21 | print_buffer(int buffer_size); 22 | ~print_buffer(void); 23 | }; 24 | -------------------------------------------------------------------------------- /Strings2Managed/process_strings.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "process_strings.h" 3 | 4 | bool IsWin64(HANDLE process) 5 | { 6 | BOOL retVal; 7 | if( IsWow64Process(process, &retVal) ) 8 | { 9 | return retVal; 10 | } 11 | PrintLastError(L"IsWow64Process"); 12 | return false; 13 | } 14 | 15 | bool process_strings::dump_system(List^ lst) 16 | { 17 | // Enumerate processes, and process the strings from each one 18 | HANDLE hSnapShot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 19 | 20 | if( hSnapShot != INVALID_HANDLE_VALUE ) 21 | { 22 | // Handle the first i_process 23 | PROCESSENTRY32 tmpProcess; 24 | tmpProcess.dwSize = sizeof(PROCESSENTRY32); 25 | int result; 26 | if( (result = Process32First(hSnapShot, &tmpProcess)) ) 27 | { 28 | if( result == TRUE ) 29 | dump_process(tmpProcess.th32ProcessID, lst); 30 | 31 | while( (result = Process32Next(hSnapShot, &tmpProcess)) ) 32 | { 33 | if( result == TRUE ) 34 | dump_process(tmpProcess.th32ProcessID, lst); 35 | } 36 | } 37 | 38 | // Cleanup the handle 39 | CloseHandle( hSnapShot ); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | bool process_strings::dump_process(DWORD pid, List^ lst) 46 | { 47 | // Open the process 48 | HANDLE ph = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid); 49 | if( ph != NULL ) 50 | { 51 | // Assign the process name 52 | TCHAR* process_name_w = new TCHAR[0x100]; 53 | process_name_w[0] = 0; 54 | GetModuleBaseName(ph, 0, process_name_w, 0x100 ); 55 | char* process_name = new char[0x100]; 56 | process_name[0] = 0; 57 | 58 | // Convert from wchar to char filename 59 | wcstombs( process_name, process_name_w, 0x100 ); 60 | 61 | // Generate the module list 62 | HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); 63 | if ( hSnapshot != INVALID_HANDLE_VALUE ) 64 | { 65 | this->generateModuleList(hSnapshot); 66 | CloseHandle(hSnapshot); 67 | 68 | // Walk through the process heaps, extracting the strings 69 | bool result = this->processAllHeaps(ph, process_name, lst); 70 | 71 | free(process_name); 72 | return result; 73 | }else{ 74 | fprintf(stderr,"Failed gather module information for process 0x%x (%i). ", pid, pid); 75 | PrintLastError(L"dump_process"); 76 | } 77 | 78 | free(process_name); 79 | return false; 80 | }else{ 81 | fprintf(stderr,"Failed open process 0x%x (%i). ", pid, pid); 82 | PrintLastError(L"dump_process"); 83 | } 84 | } 85 | 86 | process_strings::process_strings(string_parser* parser) 87 | { 88 | this->parser = parser; 89 | } 90 | 91 | 92 | bool process_strings::processAllHeaps(HANDLE ph, char* process_name, List^ lst) 93 | { 94 | // Set the max address of the target process. Assume it is a 64 bit process. 95 | __int64 maxAddress = 0; 96 | maxAddress = 0x7ffffffffff; 97 | 98 | // Walk the process heaps 99 | __int64 address = 0; 100 | MEMORY_BASIC_INFORMATION mbi; 101 | 102 | while (address < maxAddress) 103 | { 104 | // Load this heap information 105 | __int64 blockSize = VirtualQueryEx(ph, (LPCVOID) address, (_MEMORY_BASIC_INFORMATION*) &mbi, sizeof(_MEMORY_BASIC_INFORMATION64)); 106 | __int64 newAddress = (__int64)mbi.BaseAddress + (__int64)mbi.RegionSize + (__int64)1; 107 | if( newAddress <= address ) 108 | break; 109 | address = newAddress; 110 | 111 | if( mbi.State == MEM_COMMIT && !(mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) ) 112 | { 113 | // Process this heap 114 | 115 | // Read in the heap 116 | unsigned char* buffer = new unsigned char[mbi.RegionSize]; 117 | if( buffer != NULL ) 118 | { 119 | __int64 numRead = 0; 120 | bool result = ReadProcessMemory(ph, (LPCVOID) mbi.BaseAddress, buffer, mbi.RegionSize,(SIZE_T*) &numRead); 121 | 122 | //fprintf(stderr,"Current address: %016llX\n",mbi.BaseAddress); 123 | if( numRead > 0 ) 124 | { 125 | if( numRead != (unsigned int) mbi.RegionSize ) 126 | fprintf(stderr,"Failed read full heap from address 0x%016llX: %s. Only %i of expected %i bytes were read.\n", mbi.BaseAddress, strerror(errno), numRead, mbi.RegionSize); 127 | 128 | // Print the strings from this heap 129 | parser->parse_block( buffer, numRead, process_name, lst); 130 | }else if( !result ){ 131 | fprintf(stderr,"Failed to read from address 0x%016llX. ", mbi.BaseAddress); 132 | PrintLastError(L"ReadProcessMemory"); 133 | } 134 | 135 | // Cleanup 136 | free(buffer); 137 | }else{ 138 | fprintf(stderr,"Failed to allocate space of %x for reading in a heap.", mbi.RegionSize); 139 | } 140 | } 141 | } 142 | 143 | return true; 144 | } 145 | 146 | void process_strings::generateModuleList(HANDLE hSnapshot) 147 | { 148 | MODULEENTRY32 tmpModule; 149 | tmpModule.dwSize = sizeof(MODULEENTRY32); 150 | if( Module32First(hSnapshot, &tmpModule) ) 151 | { 152 | // Add this i_module to our array 153 | tmpModule.dwSize = sizeof(MODULEENTRY32); 154 | modules.Add(new module(tmpModule)); 155 | 156 | while(Module32Next(hSnapshot,&tmpModule)) 157 | { 158 | // Add this i_module to our array 159 | modules.Add(new module(tmpModule)); 160 | tmpModule.dwSize = sizeof(MODULEENTRY32); 161 | } 162 | } 163 | } 164 | 165 | process_strings::~process_strings(void) 166 | { 167 | } 168 | -------------------------------------------------------------------------------- /Strings2Managed/process_strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "windows.h" 3 | #include "module.h" 4 | #include 5 | #include "string_parser.h" 6 | #include 7 | #include "basics.h" 8 | #pragma comment(lib, "Psapi") 9 | #include 10 | 11 | using namespace std; 12 | using namespace System; 13 | using namespace System::Collections::Generic; 14 | using namespace System::Diagnostics; 15 | using namespace System::Text; 16 | using namespace System::IO; 17 | using namespace System::Text::RegularExpressions; 18 | 19 | 20 | class process_strings 21 | { 22 | DynArray modules; 23 | string_parser* parser; 24 | 25 | void generateModuleList(HANDLE hSnapshot); 26 | bool processAllHeaps(HANDLE ph, char* process_name, List^ lst); 27 | public: 28 | process_strings(string_parser* parser); 29 | bool dump_process(DWORD pid, List^ lst); 30 | bool dump_system(List^ lst); 31 | ~process_strings(void); 32 | }; 33 | -------------------------------------------------------------------------------- /Strings2Managed/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by app.rc 4 | -------------------------------------------------------------------------------- /Strings2Managed/string_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "StdAfx.h" 2 | #include "assert.h" 3 | #include "string_parser.h" 4 | #include "strings2.h" 5 | #include "Strings2ManagedWrapper.h" 6 | #include 7 | #include 8 | 9 | using namespace System; 10 | using namespace msclr::interop; 11 | using namespace System::Collections; 12 | 13 | 14 | int string_parser::extractImmediate( char* immediate, int immediateSize, STRING_TYPE &stringType, unsigned char* outputString ) 15 | { 16 | // Extract unicode or ascii from the immediate constant. 17 | // Assumes: outputString + 4 is a valid address. 18 | int i = 0; 19 | switch(stringType) 20 | { 21 | case TYPE_ASCII: 22 | // Parse the immediate as ascii 23 | while( i < immediateSize && isAscii[immediate[i]] ) 24 | { 25 | *outputString = immediate[i]; 26 | outputString++; 27 | i++; 28 | } 29 | return i; 30 | 31 | case TYPE_UNICODE: 32 | // Parse the immediate as unicode 33 | while( i+1 < immediateSize && isAscii[immediate[i]] && immediate[i+1] == 0 ) 34 | { 35 | *outputString = immediate[i]; 36 | outputString++; 37 | i+=2; 38 | } 39 | return i/2; 40 | 41 | case TYPE_UNDETERMINED: 42 | // Determine if this is ascii or unicode 43 | if( !isAscii[immediate[0]] ) 44 | { 45 | // Not unicode or ascii, return. 46 | return 0; 47 | }else if( immediateSize > 1 && immediate[1] == 0 ) 48 | { 49 | // Recurse as Unicode 50 | stringType = TYPE_UNICODE; 51 | return extractImmediate( immediate, immediateSize, stringType, outputString ); 52 | }else{ 53 | // Recurse as Ascii 54 | stringType = TYPE_ASCII; 55 | return extractImmediate( immediate, immediateSize, stringType, outputString ); 56 | } 57 | 58 | default: 59 | break; 60 | } 61 | return 0; 62 | } 63 | 64 | int string_parser::extractString( unsigned char* buffer, long bufferSize, long offset, unsigned char* outputString, int outputStringSize, int &outputStringLength, EXTRACT_TYPE & extractType, STRING_TYPE & stringType) 65 | { 66 | // Process the string as either: 67 | // 1. ascii 68 | // 2. unicode 69 | // 3. x86 ASM stack pushes 70 | // TODO: 4. x64 ASM stack pushes 71 | // 72 | // To improve performance: 73 | // Assumes MAX_STRING_SIZE > 1 74 | // Assumes MinStringSize > 1 75 | // Assumes offset + 3 < bufferSize 76 | // These assumptions must be validated by the calling function. 77 | 78 | // Supported string push formats 79 | // C6 45 mov byte [ebp+imm8], imm8 80 | // C6 85 mov byte [ebp+imm32], imm8 81 | // 66 C7 45 mov word [ebp+imm8], imm16 82 | // 66 C7 85 mov word [ebp+imm32], imm16 83 | // C7 45 mov dword [ebp+imm8], imm32 84 | // C7 85 mov dword [ebp+imm32], imm32 85 | 86 | // Set unknown string type 87 | extractType = EXTRACT_RAW; 88 | outputStringLength = 0; 89 | int i = 0; 90 | int instSize; 91 | int immSize; 92 | int immOffset; 93 | int maxStringSize; 94 | int size; 95 | 96 | 97 | unsigned _int16 value = *((unsigned _int16*) (buffer+offset)); 98 | // Switch on the first two bytes 99 | switch( value ) 100 | { 101 | case 0x45C6: 102 | // 0 1 0 [0] 103 | // C6 45 mov byte [ebp+imm8], imm8 104 | instSize = 4; 105 | immSize = 1; 106 | immOffset = instSize - immSize; 107 | maxStringSize = 1; 108 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 109 | && buffer[offset+i] == 0xC6 && buffer[offset+i+1] == 0x45 ) 110 | { 111 | 112 | // Process this immediate 113 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 114 | outputString += size; 115 | outputStringLength += size; 116 | 117 | i+=instSize; 118 | 119 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 120 | || (stringType == TYPE_ASCII && size < immSize ) ) 121 | break; 122 | } 123 | extractType = EXTRACT_ASM; 124 | return i; 125 | 126 | case 0x85C6: 127 | // 0 1 0 1 2 3 4 [0] 128 | // C6 85 mov byte [ebp+imm32], imm8 129 | instSize = 8; 130 | immSize = 1; 131 | immOffset = instSize - immSize; 132 | maxStringSize = 1; 133 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 134 | && buffer[offset+i] == 0xC6 && buffer[offset+i+1] == 0x85 ) 135 | { 136 | 137 | // Process this immediate 138 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 139 | outputString += size; 140 | outputStringLength += size; 141 | 142 | i+=instSize; 143 | 144 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 145 | || (stringType == TYPE_ASCII && size < immSize ) ) 146 | break; 147 | } 148 | extractType = EXTRACT_ASM; 149 | return i; 150 | 151 | case 0x45C7: 152 | // 0 1 0 [0 1 2 3] 153 | // C7 45 mov dword [ebp+imm8], imm32 154 | instSize = 7; 155 | immSize = 4; 156 | immOffset = instSize - immSize; 157 | maxStringSize = 4; 158 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 159 | && buffer[offset+i] == 0xC7 && buffer[offset+i+1] == 0x45 ) 160 | { 161 | 162 | // Process this immediate 163 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 164 | outputString += size; 165 | outputStringLength += size; 166 | 167 | i+=instSize; 168 | 169 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 170 | || (stringType == TYPE_ASCII && size < immSize ) ) 171 | break; 172 | } 173 | extractType = EXTRACT_ASM; 174 | return i; 175 | 176 | case 0x85C7: 177 | // 0 1 0 1 2 3 [0 1 2 3] 178 | // C7 85 mov dword [ebp+imm32], imm32 179 | instSize = 10; 180 | immSize = 4; 181 | immOffset = instSize - immSize; 182 | maxStringSize = 4; 183 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 184 | && buffer[offset+i] == 0xC7 && buffer[offset+i+1] == 0x85 ) 185 | { 186 | 187 | // Process this immediate 188 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 189 | outputString += size; 190 | outputStringLength += size; 191 | 192 | i+=instSize; 193 | 194 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 195 | || (stringType == TYPE_ASCII && size < immSize ) ) 196 | break; 197 | } 198 | extractType = EXTRACT_ASM; 199 | return i; 200 | 201 | case 0xC766: 202 | if( buffer[offset+2] == 0x45 ) 203 | { 204 | // 0 1 2 0 [0 1] 205 | // 66 C7 45 mov word [ebp+imm8], imm16 206 | instSize = 6; 207 | immSize = 2; 208 | immOffset = instSize - immSize; 209 | maxStringSize = 2; 210 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 211 | && buffer[offset+i] == 0x66 && buffer[offset+i+1] == 0xC7 && buffer[offset+i+2] == 0x45 ) 212 | { 213 | 214 | // Process this immediate 215 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 216 | outputString += size; 217 | outputStringLength += size; 218 | 219 | i+=instSize; 220 | 221 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 222 | || (stringType == TYPE_ASCII && size < immSize ) ) 223 | break; 224 | } 225 | extractType = EXTRACT_ASM; 226 | return i; 227 | }else if( buffer[offset+2] == 0x85 ) 228 | { 229 | // 0 1 2 0 1 2 3 [0 1] 230 | // 66 C7 85 mov word [ebp+imm32], imm16 231 | i = 0; 232 | instSize = 9; 233 | immSize = 2; 234 | immOffset = instSize - immSize; 235 | maxStringSize = 2; 236 | while( offset+i+instSize < bufferSize && outputStringLength + maxStringSize < outputStringSize 237 | && buffer[offset+i] == 0x66 && buffer[offset+i+1] == 0xC7 && buffer[offset+i+2] == 0x85 ) 238 | { 239 | 240 | // Process this immediate 241 | size = this->extractImmediate( (char*) (buffer + offset + immOffset + i), immSize, stringType, outputString ); 242 | outputString += size; 243 | outputStringLength += size; 244 | 245 | i+=instSize; 246 | 247 | if( (stringType == TYPE_UNICODE && size < ((immSize + 1) / 2) ) 248 | || (stringType == TYPE_ASCII && size < immSize ) ) 249 | break; 250 | } 251 | extractType = EXTRACT_ASM; 252 | return i; 253 | } 254 | break; 255 | 256 | default: 257 | // Try to parse as ascii or unicode 258 | if( isAscii[buffer[offset]] ) 259 | { 260 | // Consider unicode case 261 | if( buffer[offset+1] == 0 ) // No null dereference by assumptions 262 | { 263 | // Parse as unicode 264 | while( offset+i+1 < bufferSize && i/2 < outputStringSize && isAscii[buffer[offset+i]] && buffer[offset+i+1] == 0 && i/2 + 1 < outputStringSize ) 265 | { 266 | // Copy this character 267 | outputString[i/2] = buffer[offset+i]; 268 | 269 | i+=2; 270 | } 271 | outputStringLength = i / 2; 272 | stringType = TYPE_UNICODE; 273 | return i; 274 | }else 275 | { 276 | // Parse as ascii 277 | i = offset; 278 | while( i < bufferSize && isAscii[buffer[i]] ) 279 | i++; 280 | outputStringLength = i - offset; 281 | if( outputStringLength > outputStringSize ) 282 | outputStringLength = outputStringSize; 283 | 284 | // Copy this string to the output 285 | memcpy( outputString, buffer + offset, outputStringLength ); 286 | stringType = TYPE_ASCII; 287 | return outputStringLength; 288 | } 289 | } 290 | } 291 | 292 | outputStringLength = 0; 293 | return 0; 294 | } 295 | 296 | 297 | bool string_parser::processContents(unsigned char* filecontents, long bufferSize, LPCSTR filename, List^ lst) 298 | { 299 | 300 | // Process the contents of the specified file, and build the list of strings 301 | unsigned char* outputString = new unsigned char[MAX_STRING_SIZE+1]; 302 | int totalsize = 100000; 303 | int outputStringSize = 0; 304 | 305 | long offset = 0; 306 | EXTRACT_TYPE extractType; 307 | while( offset + options.minCharacters < bufferSize ) 308 | { 309 | // Process this offset 310 | STRING_TYPE stringType = TYPE_UNDETERMINED; 311 | int stringDiskSpace = extractString( filecontents, bufferSize, offset, outputString, MAX_STRING_SIZE, outputStringSize, extractType, stringType ); 312 | 313 | if( outputStringSize >= options.minCharacters ) 314 | { 315 | // Print the resulting string 316 | outputString[outputStringSize] = 0; 317 | 318 | 319 | // Decide if we should print this 320 | bool print = true; 321 | if( options.printNormal && extractType == EXTRACT_RAW ) 322 | print = true; 323 | else if( options.printASM && extractType == EXTRACT_ASM ) 324 | print = true; 325 | 326 | if( options.printUnicodeOnly && stringType != TYPE_UNICODE ) 327 | print = true; 328 | if( options.printAsciiOnly && stringType != TYPE_ASCII ) 329 | print = true; 330 | 331 | if( print ) 332 | { 333 | // Replace \n with "\\n" and \r with "\\r" 334 | if( options.escapeNewLines ) 335 | { 336 | int i = 0; 337 | while( i < outputStringSize && outputStringSize + 2 < MAX_STRING_SIZE ) 338 | { 339 | if( outputString[i] == '\n' ) 340 | { 341 | memmove(outputString+i+2, outputString+i+1, (outputStringSize) - i); 342 | outputString[i] = '\\'; 343 | outputString[i+1] = 'n'; 344 | outputStringSize++; 345 | }else if( outputString[i] == '\r' ) 346 | { 347 | memmove(outputString+i+2, outputString+i+1, (outputStringSize) - i); 348 | outputString[i] = '\\'; 349 | outputString[i+1] = 'r'; 350 | outputStringSize++; 351 | } 352 | i++; 353 | } 354 | } 355 | 356 | if( (!options.printUniqueLocal && !options.printUniqueGlobal)) 357 | { 358 | WCHAR s[MAX_LENGTH + MAX_STRING_SIZE] = {0}; 359 | 360 | if( options.printType && options.printFile ) 361 | swprintf(s, L"%S %S %S %S", (char*)filename, ",", (extractType == EXTRACT_RAW ? (stringType == TYPE_UNICODE ? "UNICODE: " : (stringType == TYPE_ASCII ? "ASCII: " : "UNDETERMINED: ")) : "ASM: "), (char*)outputString); 362 | else if( options.printType ) 363 | swprintf(s, L"%S %S", (extractType == EXTRACT_RAW ? (stringType == TYPE_UNICODE ? "UNICODE: " : (stringType == TYPE_ASCII ? "ASCII: " : "UNDETERMINED: ")) : "ASM: "), (char*)outputString); 364 | else if( options.printFile ) 365 | swprintf(s, L"%S %S %S", (char*)filename, ": ", (char*)outputString); 366 | else 367 | swprintf(s, L"%S", (char*)outputString); 368 | 369 | marshal_context^ context = gcnew marshal_context(); 370 | String^ ms = context->marshal_as(s); 371 | lst->Add(ms); 372 | delete context; 373 | 374 | } 375 | 376 | } 377 | 378 | // Advance the offset 379 | offset += stringDiskSpace; 380 | }else{ 381 | // Advance the offset by 1 382 | offset += 1; 383 | } 384 | } 385 | 386 | delete[] outputString; 387 | return true; 388 | } 389 | 390 | 391 | bool string_parser::parse_block(unsigned char* buffer, unsigned int buffer_length, LPCSTR datasource, List^ lst) 392 | { 393 | if( buffer != NULL && buffer_length > 0) 394 | { 395 | // Process this buffer 396 | return this->processContents(buffer, buffer_length, datasource, lst); 397 | } 398 | return false; 399 | } 400 | 401 | string_parser::string_parser(STRING_OPTIONS options) 402 | { 403 | printer = new print_buffer(0x100000); 404 | this->options = options; 405 | } 406 | 407 | bool string_parser::parse_stream(FILE* fh, LPCSTR datasource, List^ lst) 408 | { 409 | 410 | if( fh != NULL ) 411 | { 412 | 413 | unsigned char* buffer; 414 | int numRead; 415 | 416 | // Allocate the buffer 417 | 418 | do 419 | { 420 | buffer = new unsigned char[BLOCK_SIZE]; 421 | 422 | // Read the stream in blocks of 0x50000, assuming that a string does not border the regions. 423 | numRead = fread( buffer, 1, BLOCK_SIZE - 1, fh); 424 | buffer[numRead] = 0; 425 | 426 | if( numRead > 0 ) 427 | { 428 | // We have read in the full contents now, lets process it. 429 | this->processContents(buffer, numRead, datasource, lst); 430 | 431 | } 432 | } while (!feof(fh)); 433 | 434 | // Clean up 435 | delete[] buffer; 436 | return true; 437 | }else{ 438 | // Failed to open file 439 | fprintf(stderr,"Invalid stream: %s.\n", strerror(errno)); 440 | return false; 441 | } 442 | } 443 | 444 | string_parser::~string_parser(void) 445 | { 446 | delete printer; 447 | } 448 | -------------------------------------------------------------------------------- /Strings2Managed/string_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "windows.h" 4 | #include "DynArray.h" 5 | #include "print_buffer.h" 6 | #include 7 | 8 | using namespace std; 9 | using namespace System; 10 | using namespace System::Collections::Generic; 11 | using namespace System::Diagnostics; 12 | using namespace System::Text; 13 | using namespace System::IO; 14 | using namespace System::Text::RegularExpressions; 15 | 16 | using namespace std; 17 | 18 | #define MAX_STRING_SIZE 0x2000 19 | #define BLOCK_SIZE 0x5000 20 | 21 | 22 | // Quick way of checking if a character value is displayable ascii 23 | static bool isAscii[0x100] = 24 | /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 25 | /* 0x00 */ {false,false,false,false, false,false,false,false, false,true ,true ,false, false,true ,false,false, 26 | /* 0x10 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 27 | /* 0x20 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , 28 | /* 0x30 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , 29 | /* 0x40 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , 30 | /* 0x50 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , 31 | /* 0x60 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , 32 | /* 0x70 */ true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,true , true ,true ,true ,false, 33 | /* 0x80 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 34 | /* 0x90 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 35 | /* 0xA0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 36 | /* 0xB0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 37 | /* 0xC0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 38 | /* 0xD0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 39 | /* 0xE0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false, 40 | /* 0xF0 */ false,false,false,false, false,false,false,false, false,false,false,false, false,false,false,false}; 41 | 42 | struct STRING_OPTIONS 43 | { 44 | bool printAsciiOnly; 45 | bool printUnicodeOnly; 46 | bool printFile; 47 | bool printType; 48 | bool printNormal; 49 | bool printASM; 50 | bool printUniqueLocal; 51 | bool printUniqueGlobal; 52 | bool escapeNewLines; 53 | int minCharacters; 54 | }; 55 | 56 | class string_parser 57 | { 58 | // Maybe add XOR methods for extracting strings? 59 | enum EXTRACT_TYPE 60 | { 61 | EXTRACT_RAW, 62 | EXTRACT_ASM 63 | }; 64 | 65 | enum STRING_TYPE 66 | { 67 | TYPE_UNDETERMINED, 68 | TYPE_ASCII, 69 | TYPE_UNICODE 70 | }; 71 | 72 | STRING_OPTIONS options; 73 | print_buffer* printer; 74 | 75 | 76 | int extractImmediate( char* immediate, int immediateSize, STRING_TYPE &stringType, unsigned char* outputString ); 77 | int extractString( unsigned char* buffer, long bufferSize, long offset, unsigned char* outputString, int outputStringSize, int &outputStringLength, EXTRACT_TYPE &extractType, STRING_TYPE & stringType); 78 | bool processContents(unsigned char* buffer, long numRead, LPCSTR filepath, List^ lst); 79 | public: 80 | string_parser( STRING_OPTIONS options ); 81 | bool parse_block(unsigned char* buffer, unsigned int buffer_length, LPCSTR datasource, List^ lst); 82 | bool parse_stream(FILE* fh, LPCSTR datasource, List^ lst); 83 | ~string_parser(void); 84 | }; -------------------------------------------------------------------------------- /Strings2Managed/strings2.cpp: -------------------------------------------------------------------------------- 1 | // Modified By Javelin Networks. 2 | // strings.cpp : Defines the entry point for the console application. 3 | // 4 | 5 | #include "stdafx.h" 6 | #include "string_parser.h" 7 | #include "windows.h" 8 | #include 9 | #include "dirent.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "process_strings.h" 18 | #include "strings2.h" 19 | 20 | using namespace System; 21 | using namespace msclr::interop; 22 | using namespace System::Collections; 23 | 24 | using namespace std; 25 | 26 | 27 | BOOL Is64BitWindows() 28 | { 29 | #if defined(_WIN64) 30 | return TRUE; // 64-bit programs run only on Win64 31 | #elif defined(_WIN32) 32 | // 32-bit programs run on both 32-bit and 64-bit Windows 33 | // so must sniff 34 | BOOL f64 = FALSE; 35 | return IsWow64Process(GetCurrentProcess(), &f64) && f64; 36 | #else 37 | return FALSE; // Win64 does not support Win16 38 | #endif 39 | } 40 | 41 | bool isElevated(HANDLE h_Process) 42 | { 43 | HANDLE h_Token; 44 | TOKEN_ELEVATION t_TokenElevation; 45 | TOKEN_ELEVATION_TYPE e_ElevationType; 46 | DWORD dw_TokenLength; 47 | 48 | if (OpenProcessToken(h_Process, TOKEN_READ | TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &h_Token)) 49 | { 50 | if (GetTokenInformation(h_Token, TokenElevation, &t_TokenElevation, sizeof(t_TokenElevation), &dw_TokenLength)) 51 | { 52 | if (t_TokenElevation.TokenIsElevated != 0) 53 | { 54 | if (GetTokenInformation(h_Token, TokenElevationType, &e_ElevationType, sizeof(e_ElevationType), &dw_TokenLength)) 55 | { 56 | if (e_ElevationType == TokenElevationTypeFull || e_ElevationType == TokenElevationTypeDefault) 57 | { 58 | return true; 59 | } 60 | } 61 | } 62 | } 63 | } 64 | 65 | return false; 66 | } 67 | 68 | 69 | bool getMaximumPrivileges(HANDLE h_Process) 70 | { 71 | HANDLE h_Token; 72 | DWORD dw_TokenLength; 73 | if (OpenProcessToken(h_Process, TOKEN_READ | TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &h_Token)) 74 | { 75 | // Read the old token privileges 76 | TOKEN_PRIVILEGES* privilages = new TOKEN_PRIVILEGES[100]; 77 | if (GetTokenInformation(h_Token, TokenPrivileges, privilages, sizeof(TOKEN_PRIVILEGES) * 100, &dw_TokenLength)) 78 | { 79 | // Enable all privileges 80 | for (int i = 0; i < privilages->PrivilegeCount; i++) 81 | { 82 | privilages->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED; 83 | } 84 | 85 | // Adjust the privilges 86 | if (AdjustTokenPrivileges(h_Token, false, privilages, sizeof(TOKEN_PRIVILEGES) * 100, NULL, NULL)) 87 | { 88 | delete[] privilages; 89 | return true; 90 | } 91 | } 92 | delete[] privilages; 93 | } 94 | return false; 95 | } 96 | 97 | void mainFunction(WCHAR** infoArgs, int numInfoArgs, List^ lst) 98 | { 99 | // Process the flags 100 | WCHAR* filter = NULL; 101 | WCHAR* filePath = NULL; 102 | bool flagHelp = false; 103 | bool flagHeader = false; 104 | bool flagFile = false; 105 | bool flagFilePath = false; 106 | bool flagPrintType = false; 107 | bool flagAsmOnly = false; 108 | bool flagRawOnly = false; 109 | bool flagAsciiOnly = false; 110 | bool flagUnicodeOnly = true; 111 | bool pipedInput = !_isatty(_fileno(stdin)); 112 | bool flagPidDump = false; 113 | bool flagSystemDump = false; 114 | bool flagRecursive = false; 115 | bool flagEscape = false; 116 | int minCharacters = 4; 117 | 118 | if (numInfoArgs <= 1 && !pipedInput) 119 | flagHelp = true; 120 | 121 | for (int i = 1; i < numInfoArgs; i++) 122 | { 123 | if (lstrcmp(infoArgs[i], L"-f") == 0) 124 | flagFile = true; 125 | else if (lstrcmp(infoArgs[i], L"-file") == 0) 126 | { 127 | flagFilePath = true; 128 | 129 | if (i + 1 < numInfoArgs) 130 | { 131 | // get the file path. 132 | filePath = infoArgs[i + 1]; 133 | i++; 134 | } 135 | } 136 | else if (lstrcmp(infoArgs[i], L"-t") == 0) 137 | flagPrintType = true; 138 | else if (lstrcmp(infoArgs[i], L"-r") == 0) 139 | flagRecursive = true; 140 | else if (lstrcmp(infoArgs[i], L"-h") == 0) 141 | flagHeader = true; 142 | else if (lstrcmp(infoArgs[i], L"-asm") == 0) 143 | flagAsmOnly = true; 144 | else if (lstrcmp(infoArgs[i], L"-raw") == 0) 145 | flagRawOnly = true; 146 | else if (lstrcmp(infoArgs[i], L"-pid") == 0) 147 | flagPidDump = true; 148 | else if (lstrcmp(infoArgs[i], L"-system") == 0) 149 | flagSystemDump = true; 150 | else if (lstrcmp(infoArgs[i], L"-a") == 0) 151 | flagAsciiOnly = true; 152 | else if (lstrcmp(infoArgs[i], L"-u") == 0) 153 | flagUnicodeOnly = true; 154 | else if (lstrcmp(infoArgs[i], L"-e") == 0) 155 | flagEscape = true; 156 | else if (lstrcmp(infoArgs[i], L"-l") == 0) 157 | { 158 | if (i + 1 < numInfoArgs) 159 | { 160 | // Try to parse the number of characters 161 | int result = _wtoi(infoArgs[i + 1]); 162 | if (result >= 3) 163 | { 164 | minCharacters = result; 165 | } 166 | else{ 167 | fprintf(stderr, "Failed to parse -l argument. The string size must be 3 or larger:\n\teg. 'strings2 *.exe -l 6'\n"); 168 | exit(0); 169 | } 170 | i++; 171 | } 172 | else{ 173 | fprintf(stderr, "Failed to parse -l argument. It must be preceeded by a number:\n\teg. 'strings2 *.exe -l 6'\n"); 174 | exit(0); 175 | } 176 | } 177 | else{ 178 | // This is an unassigned argument 179 | if (filter == NULL) 180 | { 181 | filter = infoArgs[i]; 182 | } 183 | else 184 | { 185 | // This argument is an error, we already found our filter. 186 | fprintf(stderr, "Failed to parse argument number %i, '%S'. Try 'strings2 --help' for usage instructions.\n", i, infoArgs[i]); 187 | exit(0); 188 | } 189 | } 190 | } 191 | 192 | // Fill out the options structure based on the flags 193 | STRING_OPTIONS options; 194 | options.printUniqueGlobal = false; 195 | options.printUniqueLocal = false; 196 | 197 | options.printAsciiOnly = false; 198 | options.printUnicodeOnly = false; 199 | options.printNormal = false; 200 | options.printASM = false; 201 | options.escapeNewLines = flagEscape; 202 | if (flagAsmOnly) 203 | options.printASM = true; 204 | if (flagRawOnly) 205 | options.printNormal = true; 206 | if (!flagAsmOnly && !flagRawOnly) 207 | { 208 | options.printASM = true; 209 | options.printNormal = true; 210 | } 211 | 212 | if (flagAsciiOnly && flagUnicodeOnly) 213 | { 214 | fprintf(stderr, "Warning. Default conditions extract both unicode and ascii strings. There is no need to use both '-a' and '-u' flags at the same time.\n"); 215 | } 216 | else{ 217 | if (flagAsciiOnly) 218 | options.printAsciiOnly = true; 219 | if (flagUnicodeOnly) 220 | options.printUnicodeOnly = true; 221 | } 222 | 223 | 224 | options.printType = flagPrintType; 225 | options.printFile = flagFile; 226 | options.minCharacters = minCharacters; 227 | 228 | // Print copyright header 229 | if (flagHeader) 230 | { 231 | printf("Modified Strings2 v1.3\n"); 232 | printf(" Copyright © 2016, Geoff McDonald\n"); 233 | printf(" Modified by Adam Cheriki and Eyal Neemany, 2017\n"); 234 | printf(" http://www.split-code.com/\n\n"); 235 | printf(" http://www.Javelin-Networks.com\n"); 236 | } 237 | 238 | 239 | // Create the string parser object 240 | string_parser* parser = new string_parser(options); 241 | 242 | if (flagPidDump || flagSystemDump) 243 | { 244 | // Warn if running in 32 bit mode on a 64 bit OS 245 | if (Is64BitWindows() && sizeof(void*) == 4) 246 | { 247 | fprintf(stderr, "WARNING: To properly dump address spaces of 64-bit processes the 64-bit version of strings2 should be used. Currently strings2 has been detected as running as a 32bit process under a 64bit operating system.\n\n"); 248 | } 249 | 250 | // Elevate strings2 to the maximum privilges 251 | getMaximumPrivileges(GetCurrentProcess()); 252 | 253 | // Create a process string dump class 254 | process_strings* process = new process_strings(parser); 255 | 256 | if (flagPidDump) 257 | { 258 | //process->dump_process(4932); 259 | // Extract all strings from the specified process 260 | if (filter != NULL) 261 | { 262 | // Check the prefix 263 | bool isHex = false; 264 | wchar_t* prefix = new wchar_t[3]; 265 | memcpy(prefix, filter, 4); 266 | prefix[2] = 0; 267 | 268 | if (wcscmp(prefix, L"0x") == 0) 269 | { 270 | filter = &filter[2]; 271 | isHex = true; 272 | } 273 | delete[] prefix; 274 | 275 | // Extract the pid from the string 276 | unsigned int PID; 277 | if ((isHex && swscanf(filter, L"%x", &PID) > 0) || 278 | (!isHex && swscanf(filter, L"%i", &PID) > 0)) 279 | { 280 | // Successfully parsed the PID 281 | 282 | // Parse the process 283 | process->dump_process(PID, lst); 284 | 285 | 286 | } 287 | else{ 288 | fwprintf(stderr, L"Failed to parse filter argument as a valid PID: %s.\n", filter); 289 | } 290 | } 291 | else{ 292 | fwprintf(stderr, L"Error. No PID was specified. Example usage:\n\tstrings2 -pid 419 > process_strings.txt\n", filter); 293 | } 294 | } 295 | else if (flagSystemDump) 296 | { 297 | // Extract strings from the whole system 298 | process->dump_system(lst); 299 | } 300 | 301 | delete process; 302 | } 303 | else if (pipedInput) 304 | { 305 | // Set "stdin" to have binary mode: 306 | int result = _setmode(_fileno(stdin), _O_BINARY); 307 | if (result == -1) 308 | fprintf(stderr, "Failed to set piped data mode to binary but will continue with processing of piped data."); 309 | 310 | FILE* fh = fdopen(fileno(stdin), "rb"); 311 | 312 | if (fh != NULL) 313 | { 314 | // Process the piped input 315 | parser->parse_stream(fh, "piped data", lst); 316 | fclose(fh); 317 | } 318 | else{ 319 | // Error 320 | fprintf(stderr, "Invalid stream: %s.\n", "Error opening the piped input: %s.\n", strerror(errno)); 321 | } 322 | } 323 | else if (filter != NULL) 324 | { 325 | // Split the filter into the directory and filename filter halves 326 | char path[MAX_PATH + 1] = { '.', 0 }; 327 | wchar_t* last_slash = wcsrchr(filter, '\\'); 328 | if (last_slash == NULL || wcsrchr(filter, '/') > last_slash) 329 | last_slash = wcsrchr(filter, '/'); 330 | 331 | if (last_slash != NULL) 332 | { 333 | // Copy the path 334 | sprintf_s(path, MAX_PATH + 1, "%S", filter); 335 | path[last_slash - filter] = 0; 336 | 337 | // Move the filter 338 | memmove(filter, last_slash + 1, (wcslen(last_slash + 1) + 1) * 2); 339 | } 340 | 341 | } 342 | else if (flagFilePath) 343 | { 344 | char* errorMessage = "\"%ls\" is not a valid PATH\n"; 345 | 346 | try{ 347 | char fPath[5000]; 348 | *fPath = 0; 349 | sprintf_s(fPath, "%ls", filePath); 350 | FILE* file; 351 | long error = fopen_s(&file, fPath, "rb"); 352 | if (error == 0){ 353 | parser->parse_stream(file, fPath, lst); 354 | fclose(file); 355 | } 356 | else 357 | { 358 | printf(errorMessage, filePath); 359 | } 360 | } 361 | catch (int) 362 | { 363 | printf(errorMessage, filePath); 364 | } 365 | } 366 | 367 | // Cleanup the string parser 368 | delete parser; 369 | } 370 | 371 | -------------------------------------------------------------------------------- /Strings2Managed/strings2.h: -------------------------------------------------------------------------------- 1 | #include "windows.h" 2 | 3 | #include 4 | 5 | using namespace std; 6 | using namespace System; 7 | using namespace System::Collections::Generic; 8 | using namespace System::Diagnostics; 9 | using namespace System::Text; 10 | using namespace System::IO; 11 | using namespace System::Text::RegularExpressions; 12 | 13 | const int MAX_LENGTH = 10000; 14 | const int INFO_ARGS = 3; 15 | 16 | void mainFunction(WCHAR** infoArgs, int numInfoArgs, List^ lst); -------------------------------------------------------------------------------- /Strings2Managed/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // The following macros define the minimum required platform. The minimum required platform 4 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 5 | // your application. The macros work by enabling all features available on platform versions up to and 6 | // including the version specified. 7 | 8 | // Modify the following defines if you have to target a platform prior to the ones specified below. 9 | // Refer to MSDN for the latest info on corresponding values for different platforms. 10 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 11 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /Strings2Managed/x64/Release/Strings2Managed.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JavelinNetworks/IR-Tools/1e82e9592a3f5893ba39965f5d44404ddf43e697/Strings2Managed/x64/Release/Strings2Managed.dll --------------------------------------------------------------------------------