mirror of
https://github.com/TangentFoxy/love-pe.git
synced 2025-07-28 02:02:16 +00:00
The library can now replace the icon of an executable
This commit is contained in:
63
love-pe.lua
63
love-pe.lua
@@ -144,7 +144,7 @@ local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
|||||||
local NumberOfNameEntries = decodeNumber(exeFile:read(2),true)
|
local NumberOfNameEntries = decodeNumber(exeFile:read(2),true)
|
||||||
local NumberOfIDEntries = decodeNumber(exeFile:read(2),true)
|
local NumberOfIDEntries = decodeNumber(exeFile:read(2),true)
|
||||||
|
|
||||||
print("--readResourceDirectoryTable",RootOffset,Level,MajorVersion,MinorVersion,TimeDateStamp,NumberOfNameEntries,NumberOfIDEntries)
|
--print("--readResourceDirectoryTable",RootOffset,Level,MajorVersion,MinorVersion,TimeDateStamp,NumberOfNameEntries,NumberOfIDEntries)
|
||||||
|
|
||||||
--Parse Entries
|
--Parse Entries
|
||||||
for i=1,NumberOfNameEntries+NumberOfIDEntries do
|
for i=1,NumberOfNameEntries+NumberOfIDEntries do
|
||||||
@@ -164,7 +164,7 @@ local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
|||||||
--Decode UTF-16LE string
|
--Decode UTF-16LE string
|
||||||
Name = decodeUTF16(exeFile:read(NameLength*2))
|
Name = decodeUTF16(exeFile:read(NameLength*2))
|
||||||
|
|
||||||
print("Name Entry",Name)
|
--print("Name Entry",Name)
|
||||||
else
|
else
|
||||||
--Name is an ID
|
--Name is an ID
|
||||||
Name = band(Name,0xFFFF)
|
Name = band(Name,0xFFFF)
|
||||||
@@ -174,14 +174,14 @@ local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
|||||||
Name = resourcesTypes[Name]
|
Name = resourcesTypes[Name]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
print("ID Entry",Name)
|
--print("ID Entry",Name)
|
||||||
end
|
end
|
||||||
|
|
||||||
if band(Offset,0x80000000) ~= 0 then
|
if band(Offset,0x80000000) ~= 0 then
|
||||||
--Another directory
|
--Another directory
|
||||||
exeFile:seek(RootOffset + band(Offset,0x7FFFFFFF))
|
exeFile:seek(RootOffset + band(Offset,0x7FFFFFFF))
|
||||||
|
|
||||||
print("Another Directory")
|
--print("Another Directory")
|
||||||
|
|
||||||
Tree[Name] = readResourceDirectoryTable(exeFile,Sections,RootOffset,Level+1)
|
Tree[Name] = readResourceDirectoryTable(exeFile,Sections,RootOffset,Level+1)
|
||||||
else
|
else
|
||||||
@@ -192,7 +192,7 @@ local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
|||||||
local DataSize = decodeNumber(exeFile:read(4),true)
|
local DataSize = decodeNumber(exeFile:read(4),true)
|
||||||
local DataCodepage = decodeNumber(exeFile:read(4),true)
|
local DataCodepage = decodeNumber(exeFile:read(4),true)
|
||||||
|
|
||||||
print("DATA",DataRVA,DataSize,DataCodepage)
|
--print("DATA",DataRVA,DataSize,DataCodepage)
|
||||||
if DataCodepage ~= 0 then print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") end
|
if DataCodepage ~= 0 then print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") end
|
||||||
|
|
||||||
local DataOffset = convertRVA2Offset(DataRVA,Sections)
|
local DataOffset = convertRVA2Offset(DataRVA,Sections)
|
||||||
@@ -205,7 +205,7 @@ local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
|||||||
exeFile:seek(ReturnOffset)
|
exeFile:seek(ReturnOffset)
|
||||||
end
|
end
|
||||||
|
|
||||||
print("---Directory end")
|
--print("---Directory end")
|
||||||
|
|
||||||
return Tree
|
return Tree
|
||||||
end
|
end
|
||||||
@@ -466,7 +466,12 @@ local function parsePEOptHeader(exeFile)
|
|||||||
error("ROM images are not supported !",3)
|
error("ROM images are not supported !",3)
|
||||||
end
|
end
|
||||||
|
|
||||||
exeFile:read(values.x64 and 106 or 90) --Skip 106 bytes for x64, and 90 bytes for x86
|
exeFile:read(32-2) --Skip 30 bytes
|
||||||
|
|
||||||
|
values.SectionAlignment = decodeNumber(exeFile:read(4),true)
|
||||||
|
values.FileAlignment = decodeNumber(exeFile:read(4),true)
|
||||||
|
|
||||||
|
exeFile:read(values.x64 and 108-2-38 or 92-2-38) --Skip 106 bytes for x64, and 90 bytes for x86
|
||||||
|
|
||||||
values.NumberOfRvaAndSizes = decodeNumber(exeFile:read(4),true)
|
values.NumberOfRvaAndSizes = decodeNumber(exeFile:read(4),true)
|
||||||
|
|
||||||
@@ -478,7 +483,7 @@ local function parseDataTables(exeFile,NumberOfRvaAndSizes)
|
|||||||
|
|
||||||
for i=1, NumberOfRvaAndSizes do
|
for i=1, NumberOfRvaAndSizes do
|
||||||
DataDirectories[i] = {decodeNumber(exeFile:read(4),true), decodeNumber(exeFile:read(4),true)}
|
DataDirectories[i] = {decodeNumber(exeFile:read(4),true), decodeNumber(exeFile:read(4),true)}
|
||||||
print("DataDirectory #"..i,DataDirectories[i][1],DataDirectories[i][2])
|
--print("DataDirectory #"..i,DataDirectories[i][1],DataDirectories[i][2])
|
||||||
end
|
end
|
||||||
|
|
||||||
return DataDirectories
|
return DataDirectories
|
||||||
@@ -495,7 +500,7 @@ local function parseSectionsTable(exeFile,NumberOfSections)
|
|||||||
local Sections = {}
|
local Sections = {}
|
||||||
|
|
||||||
for i=1, NumberOfSections do
|
for i=1, NumberOfSections do
|
||||||
print("\n------=Section=------",i)
|
--print("\n------=Section=------",i)
|
||||||
|
|
||||||
local Section = {}
|
local Section = {}
|
||||||
|
|
||||||
@@ -518,7 +523,7 @@ local function parseSectionsTable(exeFile,NumberOfSections)
|
|||||||
Section.Characteristics = decodeNumber(exeFile:read(4),true)
|
Section.Characteristics = decodeNumber(exeFile:read(4),true)
|
||||||
|
|
||||||
for k,v in pairs(Section) do
|
for k,v in pairs(Section) do
|
||||||
print(k,v)
|
--print(k,v)
|
||||||
end
|
end
|
||||||
|
|
||||||
Sections[i] = Section
|
Sections[i] = Section
|
||||||
@@ -642,7 +647,8 @@ function icapi.replaceIcon(exeFile,icoFile,newFile)
|
|||||||
local NumberOfSections = parseCOFFHeader(exeFile).NumberOfSections
|
local NumberOfSections = parseCOFFHeader(exeFile).NumberOfSections
|
||||||
|
|
||||||
--PE Optional Header
|
--PE Optional Header
|
||||||
local NumberOfRvaAndSizes = parsePEOptHeader(exeFile).NumberOfRvaAndSizes
|
local PEOptHeader = parsePEOptHeader(exeFile)
|
||||||
|
local NumberOfRvaAndSizes = PEOptHeader.NumberOfRvaAndSizes
|
||||||
|
|
||||||
local DataDirectoriesOffset = exeFile:tell() --Where the DataDirectories are stored
|
local DataDirectoriesOffset = exeFile:tell() --Where the DataDirectories are stored
|
||||||
|
|
||||||
@@ -669,12 +675,10 @@ function icapi.replaceIcon(exeFile,icoFile,newFile)
|
|||||||
|
|
||||||
writeTree(ResourcesTree,"/!NEW RES/")
|
writeTree(ResourcesTree,"/!NEW RES/")
|
||||||
|
|
||||||
print("Finished reading...")
|
|
||||||
|
|
||||||
local GroupID = getAnyKey(ResourcesTree["GROUP_ICON"])
|
local GroupID = getAnyKey(ResourcesTree["GROUP_ICON"])
|
||||||
|
|
||||||
removeGroupIcon(ResourcesTree,GroupID) print("Removed Icon...")
|
removeGroupIcon(ResourcesTree,GroupID)
|
||||||
addGroupIcon(ResourcesTree,GroupID,icoFile) print("Added new Icon...")
|
addGroupIcon(ResourcesTree,GroupID,icoFile)
|
||||||
|
|
||||||
local RSRC_ID = 0
|
local RSRC_ID = 0
|
||||||
|
|
||||||
@@ -685,23 +689,23 @@ function icapi.replaceIcon(exeFile,icoFile,newFile)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
print("Rebuilding resources section...")
|
|
||||||
|
|
||||||
SectionsData[RSRC_ID] = buildResourcesDirectoryTable(ResourcesTree,Sections[RSRC_ID].VirtualAddress)
|
SectionsData[RSRC_ID] = buildResourcesDirectoryTable(ResourcesTree,Sections[RSRC_ID].VirtualAddress)
|
||||||
|
|
||||||
print("Patching data tables...")
|
local function Align(value,file)
|
||||||
|
local aligner = PEOptHeader[file and "FileAlignment" or "SectionAlignment"]
|
||||||
|
return math.ceil(value/aligner)*aligner
|
||||||
|
end
|
||||||
|
|
||||||
local NewRSRCSize = #SectionsData[RSRC_ID]
|
SectionsData[RSRC_ID] = SectionsData[RSRC_ID] .. string.rep("\0",Align(#SectionsData[RSRC_ID],true)-#SectionsData[RSRC_ID])
|
||||||
|
|
||||||
|
local NewRSRCSize = Align(#SectionsData[RSRC_ID],true)
|
||||||
local OldRSRCSize = DataDirectories[3][2]
|
local OldRSRCSize = DataDirectories[3][2]
|
||||||
local ShiftOffset = NewRSRCSize - OldRSRCSize
|
local ShiftOffset = NewRSRCSize - OldRSRCSize
|
||||||
|
|
||||||
print("NEW OLD OFFSET",NewRSRCSize,OldRSRCSize,ShiftOffset)
|
|
||||||
|
|
||||||
DataDirectories[3][2] = NewRSRCSize
|
DataDirectories[3][2] = NewRSRCSize
|
||||||
--Sections[RSRC_ID].VirtualSize = Sections[RSRC_ID].VirtualSize + ShiftOffset
|
|
||||||
Sections[RSRC_ID].SizeOfRawData = Sections[RSRC_ID].SizeOfRawData + ShiftOffset
|
Sections[RSRC_ID].SizeOfRawData = Sections[RSRC_ID].SizeOfRawData + ShiftOffset
|
||||||
|
|
||||||
--[[local RSRC_Pointer = Sections[RSRC_ID].PointerToRawData
|
local RSRC_Pointer = Sections[RSRC_ID].PointerToRawData
|
||||||
|
|
||||||
for id, Section in ipairs(Sections) do
|
for id, Section in ipairs(Sections) do
|
||||||
if Sections[id].PointerToRawData > RSRC_Pointer then
|
if Sections[id].PointerToRawData > RSRC_Pointer then
|
||||||
@@ -719,19 +723,16 @@ function icapi.replaceIcon(exeFile,icoFile,newFile)
|
|||||||
if Directory[1] > Sections[RSRC_ID].VirtualAddress then
|
if Directory[1] > Sections[RSRC_ID].VirtualAddress then
|
||||||
Directory[1] = Directory[1] + ShiftOffset
|
Directory[1] = Directory[1] + ShiftOffset
|
||||||
end
|
end
|
||||||
end]]
|
end
|
||||||
|
|
||||||
print("Writing the DOS,PE,COFF and PEOpt headers...",DataDirectoriesOffset)
|
|
||||||
|
|
||||||
--Copy the DOS,PE,COFF and PEOpt headers
|
--Copy the DOS,PE,COFF and PEOpt headers
|
||||||
exeFile:seek(0)
|
exeFile:seek(0)
|
||||||
newFile:write(exeFile:read(DataDirectoriesOffset))
|
newFile:write(exeFile:read(DataDirectoriesOffset))
|
||||||
|
|
||||||
print("Writing data directories...") writeDataDirectories(newFile,DataDirectories)
|
writeDataDirectories(newFile,DataDirectories)
|
||||||
print("Writing sections table...") writeSectionsTable(newFile,Sections)
|
writeSectionsTable(newFile,Sections)
|
||||||
print("Writing sections data...") writeSections(newFile,Sections,SectionsData)
|
writeSections(newFile,Sections,SectionsData)
|
||||||
print("Writing trail data...") newFile:write(TrailData)
|
newFile:write(TrailData)
|
||||||
print("Done")
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user