mirror of
https://github.com/TangentFoxy/love-pe.git
synced 2025-07-28 02:02:16 +00:00
Huge work on the resources extractor
This commit is contained in:
152
icon-changer.lua
152
icon-changer.lua
@@ -10,6 +10,25 @@ local bit = require("bit")
|
||||
|
||||
local bor,band,lshift,rshift,tohex = bit.bor,bit.band,bit.lshift,bit.rshift,bit.tohex
|
||||
|
||||
local resourcesTypes = {
|
||||
"Cursors",
|
||||
"Bitmaps",
|
||||
"Icons",
|
||||
"Menus",
|
||||
"Dialogs",
|
||||
"String Tables",
|
||||
"Font Directories",
|
||||
"Fonts",
|
||||
"Accelerators",
|
||||
"Unformatted Resource Datas",
|
||||
"Message Tables",
|
||||
"Group Cursors",
|
||||
"13",
|
||||
"Group Icons",
|
||||
"15",
|
||||
"Version Information"
|
||||
}
|
||||
|
||||
--==Internal Functions==--
|
||||
|
||||
local function decodeNumber(str,bigEndian)
|
||||
@@ -27,6 +46,109 @@ local function decodeNumber(str,bigEndian)
|
||||
return num
|
||||
end
|
||||
|
||||
local function convertUTF16(str16)
|
||||
return str16--return str16:gsub("..","%1")
|
||||
end
|
||||
|
||||
local function convertRVA2Offset(RVA,Sections)
|
||||
for id, Section in ipairs(Sections) do
|
||||
if (Section.VirtualAddress <= RVA) and (RVA < (Section.VirtualAddress + Section.VirtualSize)) then
|
||||
return Section.PointerToRawData + (RVA - Section.VirtualAddress)
|
||||
end
|
||||
end
|
||||
error("FAILED "..tohex(RVA))
|
||||
end
|
||||
|
||||
local function readResourceDirectoryTable(exeFile,Sections,RootOffset,Level)
|
||||
local Tree = {}
|
||||
|
||||
print("---readResourceDirectoryTable",RootOffset)
|
||||
|
||||
local Characteristics = decodeNumber(exeFile:read(4))
|
||||
local TimeDateStamp = decodeNumber(exeFile:read(4))
|
||||
local MajorVersion = decodeNumber(exeFile:read(2))
|
||||
local MinorVersion = decodeNumber(exeFile:read(2))
|
||||
local NumberOfNameEntries = decodeNumber(exeFile:read(2))
|
||||
local NumberOfIDEntries = decodeNumber(exeFile:read(2))
|
||||
|
||||
print("Entries:", NumberOfNameEntries+NumberOfIDEntries)
|
||||
|
||||
--Parse Entries
|
||||
for i=1,NumberOfNameEntries+NumberOfIDEntries do
|
||||
print("Entry #"..i)
|
||||
|
||||
local Name = decodeNumber(exeFile:read(4))
|
||||
local Offset = decodeNumber(exeFile:read(4))
|
||||
|
||||
print("Offset",tohex(Offset))
|
||||
|
||||
local ReturnOffset = exeFile:tell()
|
||||
|
||||
--Parse name/id for entry
|
||||
if band(Name,0x80000000) ~= 0 then
|
||||
print("String Name")
|
||||
--Name is a string RVA
|
||||
local NameOffset = convertRVA2Offset(RootOffset + band(Name,0x7FFFFFFF), Sections)
|
||||
|
||||
exeFile:seek(NameOffset)
|
||||
|
||||
local NameLength = decodeNumber(exeFile:read(2))
|
||||
--Decode UTF-16LE string
|
||||
--Name = exeFile:read(NameLength*2)
|
||||
Name = string.char(math.random(65,90),math.random(65,90),math.random(65,90),math.random(65,90))
|
||||
|
||||
else
|
||||
--Name is an ID
|
||||
Name = band(Name,0xFFFF)
|
||||
print("Number Name",Name)
|
||||
|
||||
if Level == 0 then
|
||||
if resourcesTypes[Name] then
|
||||
Name = resourcesTypes[Name]
|
||||
print("# New name",Name)
|
||||
else
|
||||
print("Unkown type")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if band(Offset,0x80000000) ~= 0 then
|
||||
print("Another Directory")
|
||||
--Another directory
|
||||
exeFile:seek(RootOffset + band(Offset,0x7FFFFFFF))
|
||||
|
||||
Tree[Name] = readResourceDirectoryTable(exeFile,Sections,RootOffset,Level+1)
|
||||
else
|
||||
print("Data Offset",RootOffset + band(Offset,0x7FFFFFFF))
|
||||
--Data offset
|
||||
exeFile:seek(RootOffset + band(Offset,0x7FFFFFFF))
|
||||
|
||||
local DataRVA = decodeNumber(exeFile:read(4))
|
||||
local DataSize = decodeNumber(exeFile:read(4))
|
||||
local DataCodepage = decodeNumber(exeFile:read(4))
|
||||
|
||||
print("Data",tohex(DataRVA),DataSize)
|
||||
|
||||
local ok, DataOffset = pcall(convertRVA2Offset,DataRVA,Sections)
|
||||
|
||||
if ok then
|
||||
print("RVA OK")
|
||||
exeFile:seek(DataOffset)
|
||||
Tree[Name.."_P_"..tohex(DataCodepage)] = convertUTF16(exeFile:read(DataSize))
|
||||
else
|
||||
print("RVA Failed",DataOffset)
|
||||
Tree[Name] = ""
|
||||
end
|
||||
end
|
||||
|
||||
exeFile:seek(ReturnOffset)
|
||||
end
|
||||
|
||||
print("--End of tree")
|
||||
|
||||
return Tree
|
||||
end
|
||||
|
||||
--==User API==--
|
||||
|
||||
local icapi = {}
|
||||
@@ -110,23 +232,29 @@ function icapi.extractIcon(exeFile)
|
||||
end
|
||||
|
||||
--Calculate the file offset to the resources data directory
|
||||
local ResourcesOffset
|
||||
do
|
||||
local RVA = DataDirectories[3][1]
|
||||
for id, Section in ipairs(Sections) do
|
||||
if (Section.VirtualAddress <= RVA) and (RVA < (Section.VirtualAddress + Section.VirtualSize)) then
|
||||
ResourcesOffset = Section.PointerToRawData + (RVA - Section.VirtualAddress)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not ResourcesOffset then return error("Failed to calculate ResourcesOffset") end
|
||||
local ResourcesOffset = convertRVA2Offset(DataDirectories[3][1],Sections)
|
||||
|
||||
--Seek into the resources data !
|
||||
exeFile:seek(ResourcesOffset)
|
||||
|
||||
print("Offset",ResourcesOffset)
|
||||
|
||||
local ResourcesTree = readResourceDirectoryTable(exeFile,Sections,ResourcesOffset,0)
|
||||
|
||||
local function writeTree(tree,path)
|
||||
for k,v in pairs(tree) do
|
||||
if type(v) == "table" then
|
||||
love.filesystem.createDirectory(path..k)
|
||||
writeTree(v,path..k.."/")
|
||||
else
|
||||
love.filesystem.write(path..k,v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
writeTree(ResourcesTree,"/")
|
||||
|
||||
return "MEH"
|
||||
end
|
||||
|
||||
return icapi
|
Reference in New Issue
Block a user