diff --git a/icon-changer.lua b/icon-changer.lua index 32363ef..e351621 100644 --- a/icon-changer.lua +++ b/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 \ No newline at end of file