diff options
author | tobil4sk <tobil4sk@outlook.com> | 2024-07-30 15:39:41 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-30 11:39:41 -0300 |
commit | 99c7267241e6ed0ef62123187acf7a5539a6c2db (patch) | |
tree | 669b5aa0b7553e36d2179d1f57e9fbe6bcb7bb61 /win32 | |
parent | f87568a7cba69e2c19411e7a2b73016c80a14a3b (diff) | |
download | luarocks-99c7267241e6ed0ef62123187acf7a5539a6c2db.tar.gz luarocks-99c7267241e6ed0ef62123187acf7a5539a6c2db.tar.bz2 luarocks-99c7267241e6ed0ef62123187acf7a5539a6c2db.zip |
Update pe-parser to version v0.6 (#1699)
Diffstat (limited to 'win32')
-rw-r--r-- | win32/pe-parser.lua | 103 |
1 files changed, 49 insertions, 54 deletions
diff --git a/win32/pe-parser.lua b/win32/pe-parser.lua index 1aff7107..ae603a59 100644 --- a/win32/pe-parser.lua +++ b/win32/pe-parser.lua | |||
@@ -5,7 +5,7 @@ | |||
5 | -- case of 64 bit fields (bit/flag fields). Pointer arithmetic is still done numerically, so for | 5 | -- case of 64 bit fields (bit/flag fields). Pointer arithmetic is still done numerically, so for |
6 | -- very large files this could lead to undefined results. Use with care! | 6 | -- very large files this could lead to undefined results. Use with care! |
7 | -- | 7 | -- |
8 | -- Version 0.4, [copyright (c) 2013-2015 Thijs Schreijer](http://www.thijsschreijer.nl) | 8 | -- Version 0.5, [copyright (c) 2013-2018 Thijs Schreijer](http://www.thijsschreijer.nl) |
9 | -- @name pe-parser | 9 | -- @name pe-parser |
10 | -- @class module | 10 | -- @class module |
11 | 11 | ||
@@ -16,7 +16,7 @@ local M = {} | |||
16 | -- For flag fields the name is extended with `_flags`. | 16 | -- For flag fields the name is extended with `_flags`. |
17 | -- @usage -- lookup descriptive name for the myobj.Magic value | 17 | -- @usage -- lookup descriptive name for the myobj.Magic value |
18 | -- local desc = pe.const.Magic(myobj.Magic) | 18 | -- local desc = pe.const.Magic(myobj.Magic) |
19 | -- | 19 | -- |
20 | -- -- get list of flag names, indexed by flag values, for the Characteristics field | 20 | -- -- get list of flag names, indexed by flag values, for the Characteristics field |
21 | -- local flag_list = pe.const.Characteristics_flags | 21 | -- local flag_list = pe.const.Characteristics_flags |
22 | M.const = { | 22 | M.const = { |
@@ -100,7 +100,7 @@ M.const = { | |||
100 | ["800"] = "IMAGE_SCN_LNK_REMOVE", | 100 | ["800"] = "IMAGE_SCN_LNK_REMOVE", |
101 | ["1000"] = "IMAGE_SCN_LNK_COMDAT", | 101 | ["1000"] = "IMAGE_SCN_LNK_COMDAT", |
102 | ["8000"] = "IMAGE_SCN_GPREL", | 102 | ["8000"] = "IMAGE_SCN_GPREL", |
103 | ["20000"] = "IMAGE_SCN_MEM_PURGEABLE", | 103 | ["10000"] = "IMAGE_SCN_MEM_PURGEABLE", |
104 | ["20000"] = "IMAGE_SCN_MEM_16BIT", | 104 | ["20000"] = "IMAGE_SCN_MEM_16BIT", |
105 | ["40000"] = "IMAGE_SCN_MEM_LOCKED", | 105 | ["40000"] = "IMAGE_SCN_MEM_LOCKED", |
106 | ["80000"] = "IMAGE_SCN_MEM_PRELOAD", | 106 | ["80000"] = "IMAGE_SCN_MEM_PRELOAD", |
@@ -128,7 +128,7 @@ M.const = { | |||
128 | ["80000000"] = "IMAGE_SCN_MEM_WRITE", | 128 | ["80000000"] = "IMAGE_SCN_MEM_WRITE", |
129 | }, | 129 | }, |
130 | }, | 130 | }, |
131 | 131 | ||
132 | } | 132 | } |
133 | 133 | ||
134 | 134 | ||
@@ -143,7 +143,7 @@ function M.toHex(IN, len) | |||
143 | IN,D=math.floor(IN/B),math.fmod(IN,B)+1 | 143 | IN,D=math.floor(IN/B),math.fmod(IN,B)+1 |
144 | OUT=string.sub(K,D,D)..OUT | 144 | OUT=string.sub(K,D,D)..OUT |
145 | end | 145 | end |
146 | len = len or string.len(OUT) | 146 | len = len or #OUT |
147 | if len<1 then len = 1 end | 147 | if len<1 then len = 1 end |
148 | return (string.rep("0",len) .. OUT):sub(-len,-1) | 148 | return (string.rep("0",len) .. OUT):sub(-len,-1) |
149 | end | 149 | end |
@@ -193,8 +193,8 @@ local function get_list(list, f, add_to) | |||
193 | local r = add_to or {} | 193 | local r = add_to or {} |
194 | for i, t in ipairs(list) do | 194 | for i, t in ipairs(list) do |
195 | assert(r[t.name] == nil, "Value for '"..t.name.."' already set") | 195 | assert(r[t.name] == nil, "Value for '"..t.name.."' already set") |
196 | local val,err = f:read(t.size) -- read specified size in bytes | 196 | local val = f:read(t.size) -- read specified size in bytes |
197 | val = val or "\0" | 197 | val = val or "\0" |
198 | if t.is_str then -- entry is marked as a string value, read as such | 198 | if t.is_str then -- entry is marked as a string value, read as such |
199 | for i = 1, #val do | 199 | for i = 1, #val do |
200 | if val:sub(i,i) == "\0" then | 200 | if val:sub(i,i) == "\0" then |
@@ -248,25 +248,25 @@ end | |||
248 | -- local obj = pe.parse("c:\lua\lua.exe") | 248 | -- local obj = pe.parse("c:\lua\lua.exe") |
249 | -- obj:dump() | 249 | -- obj:dump() |
250 | M.parse = function(target) | 250 | M.parse = function(target) |
251 | 251 | ||
252 | local list = { -- list of known architectures | 252 | -- local list = { -- list of known architectures |
253 | [332] = "x86", -- IMAGE_FILE_MACHINE_I386 | 253 | -- [332] = "x86", -- IMAGE_FILE_MACHINE_I386 |
254 | [512] = "x86_64", -- IMAGE_FILE_MACHINE_IA64 | 254 | -- [512] = "x86_64", -- IMAGE_FILE_MACHINE_IA64 |
255 | [34404] = "x86_64", -- IMAGE_FILE_MACHINE_AMD64 | 255 | -- [34404] = "x86_64", -- IMAGE_FILE_MACHINE_AMD64 |
256 | } | 256 | -- } |
257 | 257 | ||
258 | local f, err = io.open(target, "rb") | 258 | local f, err = io.open(target, "rb") |
259 | if not f then return nil, err end | 259 | if not f then return nil, err end |
260 | 260 | ||
261 | local MZ = f:read(2) | 261 | local MZ = f:read(2) |
262 | if MZ ~= "MZ" then | 262 | if MZ ~= "MZ" then |
263 | f:close() | 263 | f:close() |
264 | return nil, "Not a valid image" | 264 | return nil, "Not a valid image" |
265 | end | 265 | end |
266 | 266 | ||
267 | f:seek("set", 60) -- position of PE header position | 267 | f:seek("set", 60) -- position of PE header position |
268 | local peoffset = get_int(f:read(4)) -- read position of PE header | 268 | local peoffset = get_int(f:read(4)) -- read position of PE header |
269 | 269 | ||
270 | f:seek("set", peoffset) -- move to position of PE header | 270 | f:seek("set", peoffset) -- move to position of PE header |
271 | local out = get_list({ | 271 | local out = get_list({ |
272 | { size = 4, | 272 | { size = 4, |
@@ -287,14 +287,14 @@ M.parse = function(target) | |||
287 | { size = 2, | 287 | { size = 2, |
288 | name = "Characteristics"}, | 288 | name = "Characteristics"}, |
289 | }, f) | 289 | }, f) |
290 | 290 | ||
291 | if out.PEheader ~= "PE" then | 291 | if out.PEheader ~= "PE" then |
292 | f:close() | 292 | f:close() |
293 | return nil, "Invalid PE header" | 293 | return nil, "Invalid PE header" |
294 | end | 294 | end |
295 | out.PEheader = nil -- remove it, has no value | 295 | out.PEheader = nil -- remove it, has no value |
296 | out.dump = M.dump -- export dump function as a method | 296 | out.dump = M.dump -- export dump function as a method |
297 | 297 | ||
298 | if M.toDec(out.SizeOfOptionalHeader) > 0 then | 298 | if M.toDec(out.SizeOfOptionalHeader) > 0 then |
299 | -- parse optional header; standard | 299 | -- parse optional header; standard |
300 | get_list({ | 300 | get_list({ |
@@ -388,7 +388,7 @@ M.parse = function(target) | |||
388 | if out.DataDirectory[name] then out.DataDirectory[name].name = name end | 388 | if out.DataDirectory[name] then out.DataDirectory[name].name = name end |
389 | end | 389 | end |
390 | end | 390 | end |
391 | 391 | ||
392 | -- parse section table | 392 | -- parse section table |
393 | for i = 1, M.toDec(out.NumberOfSections) do | 393 | for i = 1, M.toDec(out.NumberOfSections) do |
394 | out.Sections = out.Sections or {} | 394 | out.Sections = out.Sections or {} |
@@ -416,9 +416,9 @@ M.parse = function(target) | |||
416 | name = "Characteristics"}, | 416 | name = "Characteristics"}, |
417 | }, f) | 417 | }, f) |
418 | end | 418 | end |
419 | -- we now have section data, so add RVA conversion method | 419 | -- we now have section data, so add RVA convertion method |
420 | out.get_fileoffset = M.get_fileoffset | 420 | out.get_fileoffset = M.get_fileoffset |
421 | 421 | ||
422 | -- get the import table | 422 | -- get the import table |
423 | f:seek("set", out:get_fileoffset(out.DataDirectory.ImportTable.VirtualAddress)) | 423 | f:seek("set", out:get_fileoffset(out.DataDirectory.ImportTable.VirtualAddress)) |
424 | local done = false | 424 | local done = false |
@@ -450,7 +450,7 @@ M.parse = function(target) | |||
450 | f:seek("set", out:get_fileoffset(dll.NameRVA)) | 450 | f:seek("set", out:get_fileoffset(dll.NameRVA)) |
451 | dll.Name = readstring(f) | 451 | dll.Name = readstring(f) |
452 | end | 452 | end |
453 | 453 | ||
454 | f:close() | 454 | f:close() |
455 | return out | 455 | return out |
456 | end | 456 | end |
@@ -467,10 +467,10 @@ end | |||
467 | M.dump = function(obj) | 467 | M.dump = function(obj) |
468 | local l = 0 | 468 | local l = 0 |
469 | for k,v in pairs(obj) do if #k > l then l = #k end end | 469 | for k,v in pairs(obj) do if #k > l then l = #k end end |
470 | 470 | ||
471 | for k,v in pairs(obj) do | 471 | for k,v in pairs(obj) do |
472 | if (M.const[k] and type(v)=="string") then | 472 | if (M.const[k] and type(v)=="string") then |
473 | -- look up named value | 473 | -- look up named value |
474 | print(k..string.rep(" ", l - #k + 1)..": "..M.const[k][v]) | 474 | print(k..string.rep(" ", l - #k + 1)..": "..M.const[k][v]) |
475 | elseif M.const[k.."_flags"] then | 475 | elseif M.const[k.."_flags"] then |
476 | -- flags should be listed | 476 | -- flags should be listed |
@@ -486,14 +486,14 @@ M.dump = function(obj) | |||
486 | end | 486 | end |
487 | end | 487 | end |
488 | end | 488 | end |
489 | 489 | ||
490 | if obj.DataDirectory then | 490 | if obj.DataDirectory then |
491 | print("DataDirectory (RVA, size):") | 491 | print("DataDirectory (RVA, size):") |
492 | for i, v in ipairs(obj.DataDirectory) do | 492 | for i, v in ipairs(obj.DataDirectory) do |
493 | print(" Entry "..M.toHex(i-1).." "..pad(v.VirtualAddress,8,"0").." "..pad(v.Size,8,"0").." "..v.name) | 493 | print(" Entry "..M.toHex(i-1).." "..pad(v.VirtualAddress,8,"0").." "..pad(v.Size,8,"0").." "..v.name) |
494 | end | 494 | end |
495 | end | 495 | end |
496 | 496 | ||
497 | if obj.Sections then | 497 | if obj.Sections then |
498 | print("Sections:") | 498 | print("Sections:") |
499 | print("idx name RVA VSize Offset RawSize") | 499 | print("idx name RVA VSize Offset RawSize") |
@@ -501,7 +501,7 @@ M.dump = function(obj) | |||
501 | print(" "..i.." "..v.Name.. string.rep(" ",9-#v.Name)..pad(v.VirtualAddress,8,"0").." "..pad(v.VirtualSize,8,"0").." "..pad(v.PointerToRawData,8,"0").." "..pad(v.SizeOfRawData,8,"0")) | 501 | print(" "..i.." "..v.Name.. string.rep(" ",9-#v.Name)..pad(v.VirtualAddress,8,"0").." "..pad(v.VirtualSize,8,"0").." "..pad(v.PointerToRawData,8,"0").." "..pad(v.SizeOfRawData,8,"0")) |
502 | end | 502 | end |
503 | end | 503 | end |
504 | 504 | ||
505 | print("Imports:") | 505 | print("Imports:") |
506 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do | 506 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do |
507 | print(" "..dll.Name) | 507 | print(" "..dll.Name) |
@@ -515,7 +515,7 @@ end | |||
515 | -- used (it will only look for the dlls in the same directory). | 515 | -- used (it will only look for the dlls in the same directory). |
516 | -- @param infile binary file to check | 516 | -- @param infile binary file to check |
517 | -- @return msvcrt name (uppercase, without extension) + file where the reference was found, or nil + error | 517 | -- @return msvcrt name (uppercase, without extension) + file where the reference was found, or nil + error |
518 | function M.msvcrt(infile) | 518 | function M.msvcrt(infile) |
519 | local path, file = infile:match("(.+)\\(.+)$") | 519 | local path, file = infile:match("(.+)\\(.+)$") |
520 | if not path then | 520 | if not path then |
521 | path = "" | 521 | path = "" |
@@ -525,24 +525,34 @@ function M.msvcrt(infile) | |||
525 | end | 525 | end |
526 | local obj, err = M.parse(path..file) | 526 | local obj, err = M.parse(path..file) |
527 | if not obj then return obj, err end | 527 | if not obj then return obj, err end |
528 | 528 | ||
529 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do | 529 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do |
530 | dll = dll.Name:upper() | 530 | dll = dll.Name:upper() |
531 | local result = dll:match('(MSVCR%d*D?)%.DLL') | 531 | local result = dll:match('(MSVCR%d*D?)%.DLL') |
532 | if not result then | 532 | if not result then |
533 | result = dll:match('(MSVCRTD?)%.DLL') | 533 | result = dll:match('(MSVCRTD?)%.DLL') |
534 | end | 534 | end |
535 | if not result then | 535 | if not result then |
536 | result = dll:match('(VCRUNTIME%d*D?)%.DLL') | 536 | result = dll:match('(VCRUNTIME%d*D?)%.DLL') |
537 | end | 537 | end |
538 | if not result then | ||
539 | result = dll:match('(UCRTBASED?)%.DLL') | ||
540 | end | ||
541 | if not result then | ||
542 | -- api-ms-win-crt-xxx also indicate the universal runtime | ||
543 | result = dll:match('(API%-MS%-WIN%-CRT%-RUNTIME%-)') | ||
544 | if result then | ||
545 | result = "UCRTBASE" | ||
546 | end | ||
547 | end | ||
538 | -- success, found it return name + binary where it was found | 548 | -- success, found it return name + binary where it was found |
539 | if result then return result, infile end | 549 | if result then return result, infile end |
540 | end | 550 | end |
541 | 551 | ||
542 | -- not found, so traverse all imported dll's | 552 | -- not found, so traverse all imported dll's |
543 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do | 553 | for i, dll in ipairs(obj.DataDirectory.ImportTable) do |
544 | local rt, ref = M.msvcrt(path..dll.Name) | 554 | local rt, ref = M.msvcrt(path..dll.Name) |
545 | if rt then | 555 | if rt then |
546 | return rt, ref -- found it | 556 | return rt, ref -- found it |
547 | end | 557 | end |
548 | end | 558 | end |
@@ -550,19 +560,4 @@ function M.msvcrt(infile) | |||
550 | return nil, "No msvcrt found" | 560 | return nil, "No msvcrt found" |
551 | end | 561 | end |
552 | 562 | ||
553 | function M.get_architecture(program) | ||
554 | -- detect processor arch interpreter was compiled for | ||
555 | local proc = (M.parse(program) or {}).Machine | ||
556 | if not proc then | ||
557 | return nil, "Could not detect processor architecture used in "..program | ||
558 | end | ||
559 | proc = M.const.Machine[proc] -- collect name from constant value | ||
560 | if proc == "IMAGE_FILE_MACHINE_I386" then | ||
561 | proc = "x86" | ||
562 | else | ||
563 | proc = "x86_64" | ||
564 | end | ||
565 | return proc | ||
566 | end | ||
567 | |||
568 | return M | 563 | return M |