WildByDesign Posted December 9, 2025 Posted December 9, 2025 I have used _WinAPI_LoadString() before in a couple of projects for loading string resources. However, in those projects, I knew the string identifier. How can I get the string identifier if I don't know it? Similar to the Strings program from SysInternals, I would like to search all of the strings within a specified binary executable file to see if the string exists. I would prefer to do this entirely in AutoIt instead of using an external program. If we can get the string identifier this way, that would be fine. But ideally what I need is to just know whether or not an executable contains a specific string or not. Does anyone know if this can be done in AutoIt without any external programs? Thank you so much.
Nine Posted December 9, 2025 Posted December 9, 2025 (edited) Just make a loop : #include <WinAPI.au3> SearchString("shell32.dll", 10000, "système") Func SearchString($sDLL, $iEnd, $sString) Local $hInstance = _WinAPI_LoadLibraryEx($sDLL, $LOAD_LIBRARY_AS_DATAFILE) If Not $hInstance Then Return SetError(1) Local $sText For $i = 1 To $iEnd $sText = _WinAPI_LoadString($hInstance, $i) If @error Then ContinueLoop If StringInStr($sText, $sString) Then ConsoleWriteEx($i & " = " & $sText & @CRLF) Next _WinAPI_FreeLibrary($hInstance) EndFunc ;==>SearchString Func ConsoleWriteEx($sString) ConsoleWrite(BinaryToString(StringToBinary($sString, $SB_UTF8), $SB_ANSI)) EndFunc ;==>ConsoleWriteEx You can make the research as complex as you want... Edited December 9, 2025 by Nine Danyfirex, WildByDesign and ioa747 3 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
Solution ioa747 Posted December 9, 2025 Solution Posted December 9, 2025 (edited) @Nine beat me to it, but since I did it, I'm posting it. ... a more complicated version expandcollapse popup#include <WinAPIRes.au3> #include <WinAPILocale.au3> #include <Array.au3> _Main("AutoPlay") Func _Main($sSubstring) Local Const $sTargetDLL = "shell32.dll" ; The target DLL to scan ; Use the user's default locale ID Local $iID = 1033 ; _WinAPI_GetUserDefaultLCID() ; 1033 (Standard US English Language ID) ; Get the language name for display purposes Local $sLANGUAGE = _WinAPI_GetLocaleInfo($iID, $LOCALE_SENGLANGUAGE) ConsoleWrite("Target LCID => " & $iID & ', Language => ' & $sLANGUAGE & @CRLF) ; Pass the calculated LCID to the main function Local $aStrings = _GetAllStringsByLCIDToArray($sTargetDLL, $iID) ConsoleWrite("" & @CRLF & @CRLF) If Not IsArray($aStrings) Then ConsoleWrite("! EXTRACTION FAILED! Error code: " & @error & @CRLF) ConsoleWrite("The DLL might not contain " & $sLANGUAGE & " string resources or could not be loaded." & @CRLF) Else ConsoleWrite("- Successfully extracted " & $aStrings[0][0] & " " & $sLANGUAGE & " strings from " & $sTargetDLL & @CRLF) ConsoleWrite("- Results stored in 2D array: [Index][0]=String ID, [Index][1]=String Value" & @CRLF) For $i = 1 To $aStrings[0][0] If StringInStr($aStrings[$i][1], $sSubstring) > 0 Then ConsoleWrite($i & ") -> ID " & $aStrings[$i][0] & " -> Value: " & $aStrings[$i][1] & @CRLF) EndIf Next ; The full array ; _ArrayDisplay($aStrings) EndIf EndFunc ;==>_Main ; #FUNCTION# ==================================================================================================================== ; Name...........: _GetAllStringsByLCIDToArray ; Description....: Scans ALL String ID blocks in a DLL and returns all available strings for the specified LCID. ; Syntax.........: _GetAllStringsByLCIDToArray($sDLLName, $LCID) ; Parameters: ; $sDLLName: The path or name of the DLL (e.g., "shell32.dll"). ; $LCID: The Language Code ID (e.g., 1033 for English, 1032 for Greek, etc.). ; Returns values .: Success: A 2D array [N][2] where [N][0] is the String ID and [N][1] is the string value. ; Failure: Returns False and sets @error (1: Could not load DLL, 2: No string resources). ; =============================================================================================================================== Func _GetAllStringsByLCIDToArray($sDLLName, $LCID) Local $sLANGUAGE = _WinAPI_GetLocaleInfo($LCID, $LOCALE_SENGLANGUAGE) ; Use English name for logging Local Const $iCols = 2 ; We will store [String ID, String Value] ; Load the library as a data file Local $hInstance = _WinAPI_LoadLibraryEx($sDLLName, $LOAD_LIBRARY_AS_DATAFILE) If Not $hInstance Then Return SetError(1, 0, False) ; Could not load DLL EndIf ; Initialize the array to store the results Local $aStringData[1][$iCols] $aStringData[0][0] = 0 ; Counter for the number of found strings $aStringData[0][1] = $iCols ; Store column count ; Enumerate all string resource blocks (Type $RT_STRING) Local $aResourceNames = _WinAPI_EnumResourceNames($hInstance, $RT_STRING) If Not IsArray($aResourceNames) Then _WinAPI_FreeLibrary($hInstance) Return SetError(2, 0, False) ; No string resources found EndIf ConsoleWrite("Scanning " & $sDLLName & " for " & $sLANGUAGE & " Strings (LCID " & $LCID & ") in " & $aResourceNames[0] & " resource blocks..." & @CRLF) ; Iterate through each resource name (block) For $i = 1 To $aResourceNames[0] Local $vResourceName = $aResourceNames[$i] Local $iBlockStartID = ($vResourceName - 1) * 16 ; Iterate through all 16 potential strings in this block For $k = 0 To 15 Local $iCurrentStringID = $iBlockStartID + $k ; Use the passed LCID for loading the string Local $sString = _WinAPI_LoadStringEx($hInstance, $iCurrentStringID, $LCID) ; Process and store the string if loaded successfully If StringLen($sString) > 0 Then ; === ENHANCED CLEANING === ; Replace CR/LF with space for basic formatting $sString = StringReplace($sString, @CR, " ") $sString = StringReplace($sString, @LF, "") ; Remove non-printable control characters (e.g., SOH, EOT, ACK, NUL etc.) ; Regex: [\x00-\x08\x0B\x0C\x0E-\x1F] covers ASCII control chars (0-31) ; excluding Tab (0x09), Line Feed (0x0A), Carriage Return (0x0D). $sString = StringRegExpReplace($sString, "[\x00-\x08\x0B\x0C\x0E-\x1F]", "") ; Remove leading/trailing spaces left from replacement $sString = StringStripWS($sString, 3) ; === END CLEANING === ; Check if the string is empty after cleaning If StringLen($sString) > 0 Then $aStringData[0][0] += 1 _ArrayAdd($aStringData, "") $aStringData[$aStringData[0][0]][0] = $iCurrentStringID ; String ID $aStringData[$aStringData[0][0]][1] = $sString ; Cleaned String Value If Mod($aStringData[0][0], 500) = 0 Then ConsoleWrite(".") ; Progress indicator EndIf EndIf EndIf Next Next ; Cleanup and return result _WinAPI_FreeLibrary($hInstance) If $aStringData[0][0] > 0 Then Return $aStringData Else Return SetError(0, 0, False) EndIf EndFunc ;==>_GetAllStringsByLCIDToArray Edited December 9, 2025 by ioa747 Danyfirex and WildByDesign 2 I know that I know nothing
WildByDesign Posted December 9, 2025 Author Posted December 9, 2025 Global $sDLL = 'uxtheme.dll' ; 9,000+ resource strings Global $sDLL2 = 'C:\Windows\resources\themes\Aero\Aero.msstyles' ; 26,000+ resource strings Global $sString1 = 'DarkMode_Explorer' ; win10/11 Global $sString2 = 'DarkMode_DarkTheme' ; win11 25H2 Thank you both. For some reason, neither script seems to find the strings. I’ve confirmed with System Informer that the resource strings are there. Both of those binaries have both strings. So I’m not sure what I’m doing wrong. I posted the stuff that I am searching above.
WildByDesign Posted December 9, 2025 Author Posted December 9, 2025 This info might help narrow things down: (it is way over my head) Binary: aero.msstyles Section: .rsrc Type: Unicode Strings: DarkMode_DarkTheme::* Binary: uxtheme.dll Section: .rdata Type: Unicode String: DarkMode_DarkTheme
Nine Posted December 9, 2025 Posted December 9, 2025 Strings are not supposed to be like that (with _ and string concatenation). You are looking at the wrong place. Strings are readable humain words. WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
WildByDesign Posted December 10, 2025 Author Posted December 10, 2025 Thank you both for your time. My understanding of this was clearly wrong and I should have put more details about what I was specifically looking for in the first post. I ended up determine Windows build and revision number to know for certain whether it contained the updated theme-related files. However, given my original question, both of your answers would work great as a Solution to anyone searching the forum in the future regarding finding strings in binaries. Both scripts work great for the purpose of my original question. I actually like the simplicity of the first script but I also like the complexity of the second script as well. I'm literally going to flip a coin on this one to decide the solution because both solve the question.
WildByDesign Posted July 25 Author Posted July 25 (edited) None of us were able to figure out how to extract "unicode" specific strings from compiled binary files (.exe, .dll, etc.) at the time of this thread. But I have since needed this again to find strings of DarkMode_DarkTheme in aero.msstyles file. And in this case, I just decided to blindly ask AI to help us. And it works. We can now extract unicode strings directly from compiled binaries. No need for Strings64.exe from SysInternals now. We can use AutoIt. expandcollapse popup#include <FileConstants.au3> #include <StringConstants.au3> ;Local $sTargetDll = "C:\Windows\System32\uxtheme.dll" Local $sTargetDll = "C:\Windows\Resources\Themes\aero\aero.msstyles" ; Path to your target DLL or EXE file Local $sFilePath = $sTargetDll ; Minimum length of characters to look for (equivalent to strings64 -n switch) Local $iMinLength = 5 _ExtractStrings($sFilePath, $iMinLength) Func _ExtractStrings($sFile, $iMin) Local $hFile = FileOpen($sFile, $FO_READ + $FO_BINARY) If $hFile = -1 Then MsgBox(16, "Error", "Unable to open file: " & $sFile) Return EndIf ; Read the entire file into memory as a binary block Local $bData = FileRead($hFile) FileClose($hFile) ; Convert binary to a standard string representation for regex processing ; Note: BinaryToString with default ANSI helps parse out raw byte patterns Local $sRaw = BinaryToString($bData, $SB_ANSI) ConsoleWrite("--- SCANNING FOR ASCII STRINGS ---" & @CRLF) ; Regex to find sequences of printable ANSI characters of length >= $iMin Local $aAnsiResults = StringRegExp($sRaw, '[\x20-\x7E]{' & $iMin & ',}', 3) If Not @error Then For $i = 0 To UBound($aAnsiResults) - 1 ConsoleWrite($aAnsiResults[$i] & @CRLF) Next EndIf ConsoleWrite(@CRLF & "--- SCANNING FOR UNICODE STRINGS ---" & @CRLF) ; In UTF-16LE, standard characters are followed by a null byte (\x00). ; We look for a pattern of (PrintableChar + \x00) repeated $iMin or more times. Local $sUnicodePattern = '(?:[\x20-\x7E]\x00){' & $iMin & ',}' Local $aUnicodeMatches = StringRegExp($sRaw, $sUnicodePattern, 3) If Not @error Then For $j = 0 To UBound($aUnicodeMatches) - 1 ; Clean up the extracted UTF-16LE binary chunk back into readable text Local $sCleanText = BinaryToString(Binary($aUnicodeMatches[$j]), $SB_UTF16LE) ConsoleWrite($sCleanText & @CRLF) Next EndIf EndFunc Edited July 25 by WildByDesign argumentum and bladem2003 2
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now