Huge work on the resources extractor

This commit is contained in:
RamiLego4Game
2018-05-10 18:36:24 +03:00
parent 879dc6ed3b
commit 0f1735669e

View File

@@ -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