Что нового

[Данные, строки] Работа со строковыми ресурсами в exe

drd0s

Новичок
Сообщения
19
Репутация
2
Подскажите, пожалуйста, можно ли средствами AutoIt добавить строковый ресурс в Exe файл или перезаписать значение? Видел примеры с добавлением при помощи: AutoIt3Wrapper и какой то ResHacker которую я найти увы тоже не смог.
Хочется сделать что-то вроде лицензии в программе при помощи добавления зашифрованного ключа в ресурс самой программы. :scratch:

С уважением,
drd0s.
 

Prog

Продвинутый
Сообщения
537
Репутация
65
OffTopic:
Тогда нужно будет придумать хорошую защиту от декомпиляции, т. к. можно легко получить исходник из скомпилированной программы...
 
Автор
drd0s

drd0s

Новичок
Сообщения
19
Репутация
2
Prog сказал(а):
OffTopic:
Тогда нужно будет придумать хорошую защиту от декомпиляции, т. к. можно легко получить исходник из скомпилированной программы...
OffTopic:
Ну, насколько я слышал легко это было в AutoIt до 3 версии, может я отстал от жизни. Меня не особо тревожит, что мои исходники утекут, важнее статистика пользователей ибо без серверной части от этих исходников толку ноль. А лицензия проверяется через POST запрос на сервер как раз по ключу и данные тоже приходят с сервера.

С уважением,
drd0s.



Добавлено:
Сообщение автоматически объединено:

Если кто-то даст рабочий пример, могу накинуть $ за работу.
В итоге можно не добавлять новый ресурс, ибо это сложно насколько я понял, а редактировать уже существующий. Но каким образом я ещё не понял.

С уважением,
drd0s.
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
http://autoit-script.ru/index.php?topic=2849.0
 
Автор
drd0s

drd0s

Новичок
Сообщения
19
Репутация
2
joiner сказал(а):
http://autoit-script.ru/index.php?topic=2849.0

Уже читали...
К сожалению, у меня так и не получилось добавить что-нибудь в ресурс STRING с помощью AutoIt3Wrapper'а. Либо данные вообще не добавлялись, либо получался битый ресурс.<C>
Утилита ResHacks у меня не заработала... Интересует именно средствами AutoIt...
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
предлагаю вариант, которым пользуюсь я, не через ресурс String а через RC_DATA.
скомпилируй файл test.exe. рядом - файл lic.txt (текст лицензии, к примеру)
далее запусти код
Код:
#include <WinAPIEx.au3>
;добавляем файл
_AddRes('test.exe', 'lic.txt', 10, 'lic')
$hmod = _WinAPI_LoadLibraryEx('test.exe')
$resbyte = _GetRes($hmod, 10, 'lic')
_WinAPI_FreeLibrary($hmod)
$bts = BinaryToString($resbyte)
ConsoleWrite($bts & @LF)

;Функция: _AddRes()
;Описание: Добавляет в файл(exe) ресурсы.
;Параметры: $iPathFile - путь к исходному файлу
;           $iResFile - путь к файлу(добавляемому ресурсу)
;          $RType - тип ресурса
;           $sResName - имя ресурса после добавления(под этим именем ресурс будет находится в исполняемом файле)
;           $RLanguage - язык ресурса.
;Успех:     Возвращает - 0
;-----------------------------------------------------------------------------------------------------------------------------------
Func _AddRes($iPathFile, $iResFile, $RType, $sResName, $RLanguage = 2057)
	Local $tBuffer = 0
	If $iPathFile = '' Or $iResFile = '' Or $RType = '' Or $sResName = '' Then Return SetError(1, 0, 0)
	If StringIsDigit($RType) Then $RType = Number($RType)
	If StringIsDigit($sResName) Then $sResName = Number($sResName)
	Local $iFileSize = FileGetSize($iResFile)
	If @error = 1 Or $iFileSize = 0 Then Return SetError(2, 0, 0)
	Local $tfile = DllStructCreate('byte[' & $iFileSize & ']')
	If @error <> 0 Then Return SetError(3, @error, 0)
	Local $pfile = DllStructGetPtr($tfile)
	If $pfile = 0 Then Return SetError(4, @error, 0)
	Local $hFile = _WinAPI_CreateFile($iResFile, 2, 2)
	If $hFile = 0 Then Return SetError(5, _WinAPI_GetLastError(), 0)
	Local $iBytes = 0
	If Not _WinAPI_ReadFile($hFile, $pfile, DllStructGetSize($tfile), $iBytes) Then Return SetError(6, _WinAPI_GetLastError(), 0)
	If Not _WinAPI_CloseHandle($hFile) Then Return SetError(7, _WinAPI_GetLastError(), 0)
	Local $hUpdate = _WinAPI_BeginUpdateResource_($iPathFile)
	If Not $hUpdate = 1 Then Return SetError(9, _WinAPI_GetLastError(), 0)
	If Not _WinAPI_UpdateResource_($hUpdate, $RType, $sResName, $RLanguage, $pfile, $iBytes) Then Return SetError(10, 0, 0)
	If Not _WinAPI_EndUpdateResource_($hUpdate) Then Return SetError(11, _WinAPI_GetLastError(), 0)
EndFunc   ;==>_AddRes
;-------------------------------------------------------------------------------------------------------------------------------------
;Функция: _GetRes()
;Описание: Извлекает ресурсы из файла(exe)
;Параметры: $hInstance - дескриптор файла, из которого извлекается ресурс. для получения дескриптора можно использовать _WinAPI_LoadLibraryEx()
;          $RType - тип ресурса
;           $sResName - имя ресурса
;Успех:     Возвращает бинарные данные ресурса.
;--------------------------------------------------------------------------------------------------------------------------------------
Func _GetRes($hInstance, $RType, $sResName)
	Local $hRes = _WinAPI_FindResource($hInstance, $RType, $sResName)
	If $hRes = 0 Then Return SetError(1, 0, 0)
	Local $dSize = _WinAPI_SizeOfResource($hInstance, $hRes)
	If $dSize = 0 Then Return SetError(2, 0, 0)
	Local $hLoad = _WinAPI_LoadResource($hInstance, $hRes)
	If $hLoad = 0 Then Return SetError(3, 0, 0)
	Local $pData = _WinAPI_LockResource($hLoad)
	If $pData = 0 Then Return SetError(4, 0, 0)
	Local $tBuffer = DllStructCreate("byte[" & $dSize & "]")
	If @error <> 0 Then Return SetError(5, 0, 0)
	_WinAPI_MoveMemory(DllStructGetPtr($tBuffer), $pData, $dSize)
	Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_GetRes

Func _WinAPI_BeginUpdateResource_($sFile, $fDelete = 0)
	Local $Ret = DllCall('kernel32.dll', 'ptr', 'BeginUpdateResourceW', 'wstr', $sFile, 'int', $fDelete)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[0]
EndFunc   ;==>_WinAPI_BeginUpdateResource_

Func _WinAPI_UpdateResource_($hUpdate, $sType, $sName, $iLanguage, $pData, $iSize)
	Local $TypeOfType = 'int', $TypeOfName = 'int'
	If IsString($sType) Then
		$TypeOfType = 'wstr'
	EndIf
	If IsString($sName) Then
		$TypeOfName = 'wstr'
	EndIf
	Local $Ret = DllCall('kernel32.dll', 'int', 'UpdateResourceW', 'ptr', $hUpdate, $TypeOfType, $sType, $TypeOfName, $sName, 'ushort', $iLanguage, 'ptr', $pData, 'dword', $iSize)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_WinAPI_UpdateResource_

Func _WinAPI_EndUpdateResource_($hUpdate, $fDiscard = 0)
	Local $Ret = DllCall('kernel32.dll', 'int', 'EndUpdateResourceW', 'ptr', $hUpdate, 'int', $fDiscard)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_WinAPI_EndUpdateResource_
в консоли будет написано содержание файла ресурса. править его нельзя, но можно добавить другой с таким же именем, и ресурс файла будет заменен
функции обновления ресурса взяты из старой версии WinAPIEx. Все работоспособно

в принципе, этот же подход и предложил Yashied в теме, ссылку на которую я тебе дал
Да, в использовании ресурсов типа STRING нет ничего особо сложного, но многие наверное найдут для себя не очень удобным вызов функции _WinAPI_LoadString() для загрузки каждой строки в отдельности. Конечно можно загрузить все необходимые строки в массив в самом начале программы и далее уже ссылаться на этот массив, но все же... Есть и другой способ работы с текстом. А что нам собственно мешает записать все строки в один текстовый файл и поместить его в ресурс типа RCDATA или User-defined? Да ничего. Плюс такого подхода заключается в том, что во-первых, мы в этом случае можем обойтись одним AutoIt3Wrapper'ом, а во-вторых, можем загрузить все текстовые данные за один раз. Ну так давайте попробуем это реализовать. Как уже говорилось в предыдущем разделе, существенной разницы между RCDATA и User-defined для нас нет, поэтому я предлагаю использовать User-defined ресурс для хранения наших строк. Для начала создайте в Notepad'е текстовый файл String.txt с таки содержанием (возмем за основу предыдущий пример):

сам файл test.exe уже может читать ресурс lic из себя
Код:
#include <GUIConstantsEx.au3>
#include <WinAPIEx.au3>
$Form1 = GUICreate("Form1", 615, 438, 192, 124)
$Edit1 = GUICtrlCreateEdit("", 80, 48, 473, 313)
GUICtrlSetData(-1, "Edit1")
GUISetState(@SW_SHOW)
$hmod = _WinAPI_LoadLibraryEx(@ScriptFullPath)
$resbyte = _GetRes($hmod, 10, 'lic')
_WinAPI_FreeLibrary($hmod)
$bts = BinaryToString($resbyte)
GUICtrlSetData($Edit1,$bts)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd
 
Автор
drd0s

drd0s

Новичок
Сообщения
19
Репутация
2
joiner сказал(а):
предлагаю вариант, которым пользуюсь я, не через ресурс String а через RC_DATA.
скомпилируй файл test.exe. рядом - файл lic.txt (текст лицензии, к примеру)
далее запусти код
Код:
#include <WinAPIEx.au3>
;добавляем файл
_AddRes('test.exe', 'lic.txt', 10, 'lic')
$hmod = _WinAPI_LoadLibraryEx('test.exe')
$resbyte = _GetRes($hmod, 10, 'lic')
_WinAPI_FreeLibrary($hmod)
$bts = BinaryToString($resbyte)
ConsoleWrite($bts & @LF)

;Функция: _AddRes()
;Описание: Добавляет в файл(exe) ресурсы.
;Параметры: $iPathFile - путь к исходному файлу
;           $iResFile - путь к файлу(добавляемому ресурсу)
;          $RType - тип ресурса
;           $sResName - имя ресурса после добавления(под этим именем ресурс будет находится в исполняемом файле)
;           $RLanguage - язык ресурса.
;Успех:     Возвращает - 0
;-----------------------------------------------------------------------------------------------------------------------------------
Func _AddRes($iPathFile, $iResFile, $RType, $sResName, $RLanguage = 2057)
	Local $tBuffer = 0
	If $iPathFile = '' Or $iResFile = '' Or $RType = '' Or $sResName = '' Then Return SetError(1, 0, 0)
	If StringIsDigit($RType) Then $RType = Number($RType)
	If StringIsDigit($sResName) Then $sResName = Number($sResName)
	Local $iFileSize = FileGetSize($iResFile)
	If @error = 1 Or $iFileSize = 0 Then Return SetError(2, 0, 0)
	Local $tfile = DllStructCreate('byte[' & $iFileSize & ']')
	If @error <> 0 Then Return SetError(3, @error, 0)
	Local $pfile = DllStructGetPtr($tfile)
	If $pfile = 0 Then Return SetError(4, @error, 0)
	Local $hFile = _WinAPI_CreateFile($iResFile, 2, 2)
	If $hFile = 0 Then Return SetError(5, _WinAPI_GetLastError(), 0)
	Local $iBytes = 0
	If Not _WinAPI_ReadFile($hFile, $pfile, DllStructGetSize($tfile), $iBytes) Then Return SetError(6, _WinAPI_GetLastError(), 0)
	If Not _WinAPI_CloseHandle($hFile) Then Return SetError(7, _WinAPI_GetLastError(), 0)
	Local $hUpdate = _WinAPI_BeginUpdateResource_($iPathFile)
	If Not $hUpdate = 1 Then Return SetError(9, _WinAPI_GetLastError(), 0)
	If Not _WinAPI_UpdateResource_($hUpdate, $RType, $sResName, $RLanguage, $pfile, $iBytes) Then Return SetError(10, 0, 0)
	If Not _WinAPI_EndUpdateResource_($hUpdate) Then Return SetError(11, _WinAPI_GetLastError(), 0)
EndFunc   ;==>_AddRes
;-------------------------------------------------------------------------------------------------------------------------------------
;Функция: _GetRes()
;Описание: Извлекает ресурсы из файла(exe)
;Параметры: $hInstance - дескриптор файла, из которого извлекается ресурс. для получения дескриптора можно использовать _WinAPI_LoadLibraryEx()
;          $RType - тип ресурса
;           $sResName - имя ресурса
;Успех:     Возвращает бинарные данные ресурса.
;--------------------------------------------------------------------------------------------------------------------------------------
Func _GetRes($hInstance, $RType, $sResName)
	Local $hRes = _WinAPI_FindResource($hInstance, $RType, $sResName)
	If $hRes = 0 Then Return SetError(1, 0, 0)
	Local $dSize = _WinAPI_SizeOfResource($hInstance, $hRes)
	If $dSize = 0 Then Return SetError(2, 0, 0)
	Local $hLoad = _WinAPI_LoadResource($hInstance, $hRes)
	If $hLoad = 0 Then Return SetError(3, 0, 0)
	Local $pData = _WinAPI_LockResource($hLoad)
	If $pData = 0 Then Return SetError(4, 0, 0)
	Local $tBuffer = DllStructCreate("byte[" & $dSize & "]")
	If @error <> 0 Then Return SetError(5, 0, 0)
	_WinAPI_MoveMemory(DllStructGetPtr($tBuffer), $pData, $dSize)
	Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_GetRes

Func _WinAPI_BeginUpdateResource_($sFile, $fDelete = 0)
	Local $Ret = DllCall('kernel32.dll', 'ptr', 'BeginUpdateResourceW', 'wstr', $sFile, 'int', $fDelete)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $Ret[0]
EndFunc   ;==>_WinAPI_BeginUpdateResource_

Func _WinAPI_UpdateResource_($hUpdate, $sType, $sName, $iLanguage, $pData, $iSize)
	Local $TypeOfType = 'int', $TypeOfName = 'int'
	If IsString($sType) Then
		$TypeOfType = 'wstr'
	EndIf
	If IsString($sName) Then
		$TypeOfName = 'wstr'
	EndIf
	Local $Ret = DllCall('kernel32.dll', 'int', 'UpdateResourceW', 'ptr', $hUpdate, $TypeOfType, $sType, $TypeOfName, $sName, 'ushort', $iLanguage, 'ptr', $pData, 'dword', $iSize)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_WinAPI_UpdateResource_

Func _WinAPI_EndUpdateResource_($hUpdate, $fDiscard = 0)
	Local $Ret = DllCall('kernel32.dll', 'int', 'EndUpdateResourceW', 'ptr', $hUpdate, 'int', $fDiscard)
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_WinAPI_EndUpdateResource_
в консоли будет написано содержание файла ресурса. править его нельзя, но можно добавить другой с таким же именем, и ресурс файла будет заменен
функции обновления ресурса взяты из старой версии WinAPIEx. Все работоспособно

в принципе, этот же подход и предложил Yashied в теме, ссылку на которую я тебе дал
Да, в использовании ресурсов типа STRING нет ничего особо сложного, но многие наверное найдут для себя не очень удобным вызов функции _WinAPI_LoadString() для загрузки каждой строки в отдельности. Конечно можно загрузить все необходимые строки в массив в самом начале программы и далее уже ссылаться на этот массив, но все же... Есть и другой способ работы с текстом. А что нам собственно мешает записать все строки в один текстовый файл и поместить его в ресурс типа RCDATA или User-defined? Да ничего. Плюс такого подхода заключается в том, что во-первых, мы в этом случае можем обойтись одним AutoIt3Wrapper'ом, а во-вторых, можем загрузить все текстовые данные за один раз. Ну так давайте попробуем это реализовать. Как уже говорилось в предыдущем разделе, существенной разницы между RCDATA и User-defined для нас нет, поэтому я предлагаю использовать User-defined ресурс для хранения наших строк. Для начала создайте в Notepad'е текстовый файл String.txt с таки содержанием (возмем за основу предыдущий пример):

сам файл test.exe уже может читать ресурс lic из себя
Код:
#include <GUIConstantsEx.au3>
#include <WinAPIEx.au3>
$Form1 = GUICreate("Form1", 615, 438, 192, 124)
$Edit1 = GUICtrlCreateEdit("", 80, 48, 473, 313)
GUICtrlSetData(-1, "Edit1")
GUISetState(@SW_SHOW)
$hmod = _WinAPI_LoadLibraryEx(@ScriptFullPath)
$resbyte = _GetRes($hmod, 10, 'lic')
_WinAPI_FreeLibrary($hmod)
$bts = BinaryToString($resbyte)
GUICtrlSetData($Edit1,$bts)

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit

	EndSwitch
WEnd

Вот спасибо! Думаю этот метод мне подходит!!! :beer:
 
Верх