Last active
November 7, 2025 12:27
-
-
Save aquanox/bcfc0d087f928aefacdf49bcf0f83be1 to your computer and use it in GitHub Desktop.
PHP 8.4 FFI Windows Registry Query
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define FFI_LIB "kernel32.dll" | |
| #define FFI_SCOPE "kernel32" | |
| typedef unsigned short wchar_t; | |
| typedef int BOOL; | |
| typedef unsigned long DWORD; | |
| typedef void *PVOID; | |
| typedef PVOID HANDLE; | |
| typedef DWORD *LPDWORD; | |
| typedef unsigned short WORD; | |
| typedef wchar_t WCHAR; | |
| typedef short SHORT; | |
| typedef unsigned short USHORT; | |
| typedef unsigned int UINT; | |
| typedef char CHAR; | |
| typedef char BYTE; | |
| typedef unsigned char UBYTE; | |
| typedef WCHAR TCHAR; | |
| typedef long LSTATUS; | |
| typedef long HKEY; | |
| typedef HKEY* PHKEY; | |
| typedef DWORD ACCESS_MASK; | |
| typedef ACCESS_MASK *PACCESS_MASK; | |
| typedef ACCESS_MASK REGSAM; | |
| typedef const char* LPCSTR; | |
| typedef char* LPSTR; | |
| typedef const wchar_t* LPCWSTR; | |
| typedef wchar_t* LPWSTR; | |
| typedef BYTE* LPBYTE; | |
| LSTATUS | |
| RegOpenKeyExA( | |
| /*_In_*/ HKEY hKey, | |
| /*_In_opt_*/ LPCSTR lpSubKey, | |
| /*_In_opt_*/ DWORD ulOptions, | |
| /*_In_*/ REGSAM samDesired, | |
| /*_Out_*/ PHKEY phkResult | |
| ); | |
| LSTATUS | |
| RegOpenKeyExW( | |
| /*_In_*/ HKEY hKey, | |
| /*_In_opt_*/ LPCWSTR lpSubKey, | |
| /*_In_opt_*/ DWORD ulOptions, | |
| /*_In_*/ REGSAM samDesired, | |
| /*_Out_*/ PHKEY phkResult | |
| ); | |
| LSTATUS | |
| RegEnumValueA( | |
| /*_In_*/ HKEY hKey, | |
| /*_In_*/ DWORD dwIndex, | |
| /*_Out_writes_to_opt_(*lpcchValueName,*lpcchValueName + 1)*/ LPSTR lpValueName, | |
| /*_Inout_*/ LPDWORD lpcchValueName, | |
| /*_Reserved_*/ LPDWORD lpReserved, | |
| /*_Out_opt_*/ LPDWORD lpType, | |
| /*_Out_writes_bytes_to_opt_(*lpcbData, *lpcbData) __out_data_source(REGISTRY)*/ LPBYTE lpData, | |
| /*_Inout_opt_*/ LPDWORD lpcbData | |
| ); | |
| LSTATUS | |
| RegEnumValueW( | |
| /*_In_*/ HKEY hKey, | |
| /*_In_*/ DWORD dwIndex, | |
| /*_Out_writes_to_opt_(*lpcchValueName,*lpcchValueName + 1)*/ LPWSTR lpValueName, | |
| /*_Inout_*/ LPDWORD lpcchValueName, | |
| /*_Reserved_*/ LPDWORD lpReserved, | |
| /*_Out_opt_*/ LPDWORD lpType, | |
| /*_Out_writes_bytes_to_opt_(*lpcbData, *lpcbData) __out_data_source(REGISTRY)*/ LPBYTE lpData, | |
| /*_Inout_opt_*/ LPDWORD lpcbData | |
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| if (!extension_loaded('ffi')) | |
| die("FFI Extension is not loaded"); | |
| const ERROR_SUCCESS = 0; | |
| const ERROR_NO_MORE_ITEMS = 259; | |
| const HKEY_CLASSES_ROOT = 0x80000000; | |
| const HKEY_CURRENT_USER = 0x80000001; | |
| const HKEY_LOCAL_MACHINE = 0x80000002; | |
| const HKEY_USERS = 0x80000003; | |
| const HKEY_PERFORMANCE_DATA = 0x80000004; | |
| const HKEY_PERFORMANCE_TEXT = 0x80000050; | |
| const HKEY_PERFORMANCE_NLSTEXT = 0x80000060; | |
| const HKEY_CURRENT_CONFIG = 0x80000005; | |
| const HKEY_DYN_DATA = 0x80000006; | |
| const HKEY_CURRENT_USER_LOCAL_SETTINGS = 0x80000007; | |
| const KEY_QUERY_VALUE = (0x0001); | |
| const KEY_SET_VALUE = (0x0002); | |
| const KEY_CREATE_SUB_KEY = (0x0004); | |
| const KEY_ENUMERATE_SUB_KEYS = (0x0008); | |
| const KEY_NOTIFY = (0x0010); | |
| const KEY_CREATE_LINK = (0x0020); | |
| const KEY_WOW64_32KEY = (0x0200); | |
| const KEY_WOW64_64KEY = (0x0100); | |
| const KEY_WOW64_RES = (0x0300); | |
| const STANDARD_RIGHTS_READ = 0x00020000; | |
| const KEY_READ = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY; | |
| function EnumInstalledEngines() : array | |
| { | |
| $result = array(); | |
| $ffi = FFI::load(__DIR__ . DIRECTORY_SEPARATOR . 'ffi-kernel32.h'); | |
| $hKey = $ffi->new('HKEY'); | |
| $hResult = $ffi->RegOpenKeyExA(HKEY_CURRENT_USER, | |
| "SOFTWARE\\Epic Games\\Unreal Engine\\Builds", | |
| null, | |
| KEY_READ, | |
| FFI::addr($hKey) | |
| ); | |
| if ($hResult == ERROR_SUCCESS) | |
| { | |
| for($Index = 0;$Index < 256; ++$Index) | |
| { | |
| $ValueName = $ffi->new('CHAR[256]'); | |
| $ValueData = $ffi->new('BYTE[256]'); | |
| $ValueType = $ffi->new('DWORD'); | |
| $ValueType->cdata = 0; | |
| $ValueNameLength = $ffi->new('DWORD'); | |
| $ValueNameLength->cdata = FFI::sizeof($ValueName); | |
| $ValueDataLength = $ffi->new('DWORD'); | |
| $ValueDataLength->cdata = FFI::sizeof($ValueData); | |
| $hResult = $ffi->RegEnumValueA( | |
| $hKey->cdata, | |
| $Index, | |
| $ValueName, | |
| FFI::addr($ValueNameLength), | |
| null, | |
| FFI::addr($ValueType), | |
| $ffi->cast('LPBYTE', FFI::addr($ValueData)), | |
| FFI::addr($ValueDataLength) | |
| ); | |
| if ($hResult == ERROR_SUCCESS) | |
| { | |
| $name = FFI::string($ValueName); | |
| $data = FFI::string($ValueData); | |
| //echo "$name => $data" . PHP_EOL; | |
| $result[] = array( | |
| 'Key' => $name, | |
| 'Path' => $data | |
| ); | |
| } | |
| elseif ($hResult == ERROR_NO_MORE_ITEMS) | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| return $result; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment