WildByDesign Posted Tuesday at 02:06 PM Posted Tuesday at 02:06 PM 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 Tuesday at 03:06 PM Posted Tuesday at 03:06 PM (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 Tuesday at 03:16 PM by Nine ioa747 and WildByDesign 2 “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 Tuesday at 05:07 PM Solution Posted Tuesday at 05:07 PM (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 Tuesday at 05:37 PM by ioa747 WildByDesign 1 I know that I know nothing
WildByDesign Posted Tuesday at 09:14 PM Author Posted Tuesday at 09:14 PM 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 Tuesday at 09:58 PM Author Posted Tuesday at 09:58 PM 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 Tuesday at 11:12 PM Posted Tuesday at 11:12 PM 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 19 hours ago Author Posted 19 hours ago 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.
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