Backed out 7 changesets (bug 1876590) as requested by Gerard for causing gtest failures related to BuildIDReader.ReadFromRealLib. CLOSED TREE

Backed out changeset 9ac3a93622c8 (bug 1876590)
Backed out changeset 2cd2cc626c44 (bug 1876590)
Backed out changeset 6d978847d7dd (bug 1876590)
Backed out changeset 0b07a6f1beac (bug 1876590)
Backed out changeset 55cc3acc9297 (bug 1876590)
Backed out changeset 115753252616 (bug 1876590)
Backed out changeset c75ebb5f3a80 (bug 1876590)
This commit is contained in:
Tamas Szentpeteri 2024-05-31 08:16:07 +03:00
Родитель e08a342527
Коммит 057f862dc3
58 изменённых файлов: 276 добавлений и 2321 удалений

23
Cargo.lock сгенерированный
Просмотреть файл

@ -574,18 +574,6 @@ dependencies = [
"num_cpus", "num_cpus",
] ]
[[package]]
name = "buildid_reader"
version = "0.1.0"
dependencies = [
"goblin 0.8.1",
"libc",
"log",
"nserror",
"nsstring",
"scroll",
]
[[package]] [[package]]
name = "builtins-static" name = "builtins-static"
version = "0.1.0" version = "0.1.0"
@ -2267,7 +2255,6 @@ dependencies = [
"binary_http", "binary_http",
"bitsdownload", "bitsdownload",
"bookmark_sync", "bookmark_sync",
"buildid_reader",
"cascade_bloom_filter", "cascade_bloom_filter",
"cert_storage", "cert_storage",
"chardetng_c", "chardetng_c",
@ -2466,14 +2453,14 @@ dependencies = [
name = "goblin" name = "goblin"
version = "0.7.999" version = "0.7.999"
dependencies = [ dependencies = [
"goblin 0.8.1", "goblin 0.8.0",
] ]
[[package]] [[package]]
name = "goblin" name = "goblin"
version = "0.8.1" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2dfb858618fd40cafc83efadd02705adf6ffba765098736bd950c3c945fe0" checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887"
dependencies = [ dependencies = [
"log", "log",
"plain", "plain",
@ -3655,7 +3642,7 @@ dependencies = [
"byteorder", "byteorder",
"cfg-if", "cfg-if",
"crash-context", "crash-context",
"goblin 0.8.1", "goblin 0.8.0",
"libc", "libc",
"log", "log",
"mach2", "mach2",
@ -6182,7 +6169,7 @@ dependencies = [
"cargo_metadata", "cargo_metadata",
"fs-err", "fs-err",
"glob", "glob",
"goblin 0.8.1", "goblin 0.8.0",
"heck", "heck",
"once_cell", "once_cell",
"paste", "paste",

Просмотреть файл

@ -9,3 +9,15 @@ prefs = [
] ]
["browser_aboutRestartRequired_basic.js"] ["browser_aboutRestartRequired_basic.js"]
# Bug 1876056: re-enable once bug 1877361 is fixed
#["browser_aboutRestartRequired_buildid_false-positive.js"]
#skip-if = ["win11_2009 && msix && debug"] # bug 1823581
# Bug 1888355: re-enable once bug 1877361 is fixed
#["browser_aboutRestartRequired_buildid_mismatch.js"]
#skip-if = ["win11_2009 && msix && debug"] # bug 1823581
# Bug 1888355: re-enable once bug 1877361 is fixed
#["browser_aboutRestartRequired_buildid_no-platform-ini.js"]
#skip-if = ["win11_2009 && msix && debug"] # bug 1823581

Просмотреть файл

@ -17,6 +17,7 @@ add_task(async function test_browser_crashed_false_positive_event() {
"Build ID mismatch false positive count should be undefined" "Build ID mismatch false positive count should be undefined"
); );
ok(await ensureBuildID(), "System has correct platform.ini");
setBuildidMatchDontSendEnv(); setBuildidMatchDontSendEnv();
await forceCleanProcesses(); await forceCleanProcesses();
let eventPromise = getEventPromise("oop-browser-crashed", "false-positive"); let eventPromise = getEventPromise("oop-browser-crashed", "false-positive");

Просмотреть файл

@ -0,0 +1,56 @@
"use strict";
// On debug builds, crashing tabs results in much thinking, which
// slows down the test and results in intermittent test timeouts,
// so we'll pump up the expected timeout for this test.
requestLongerTimeout(2);
SimpleTest.expectChildProcessCrash();
add_task(async function test_browser_restartrequired_event() {
info("Waiting for oop-browser-buildid-mismatch event.");
Services.telemetry.clearScalars();
is(
getFalsePositiveTelemetry(),
undefined,
"Build ID mismatch false positive count should be undefined"
);
ok(await ensureBuildID(), "System has correct platform.ini");
let profD = Services.dirsvc.get("GreD", Ci.nsIFile);
let platformIniOrig = await IOUtils.readUTF8(
PathUtils.join(profD.path, "platform.ini")
);
let buildID = Services.appinfo.platformBuildID;
let platformIniNew = platformIniOrig.replace(buildID, "1234");
await IOUtils.writeUTF8(
PathUtils.join(profD.path, "platform.ini"),
platformIniNew,
{ flush: true }
);
setBuildidMatchDontSendEnv();
await forceCleanProcesses();
let eventPromise = getEventPromise(
"oop-browser-buildid-mismatch",
"buildid-mismatch"
);
let tab = await openNewTab(false);
await eventPromise;
await IOUtils.writeUTF8(
PathUtils.join(profD.path, "platform.ini"),
platformIniOrig,
{ flush: true }
);
unsetBuildidMatchDontSendEnv();
is(
getFalsePositiveTelemetry(),
undefined,
"Build ID mismatch false positive count should be undefined"
);
await closeTab(tab);
});

Просмотреть файл

@ -0,0 +1,50 @@
"use strict";
// On debug builds, crashing tabs results in much thinking, which
// slows down the test and results in intermittent test timeouts,
// so we'll pump up the expected timeout for this test.
requestLongerTimeout(2);
SimpleTest.expectChildProcessCrash();
add_task(async function test_browser_crashed_no_platform_ini_event() {
info("Waiting for oop-browser-buildid-mismatch event.");
Services.telemetry.clearScalars();
is(
getFalsePositiveTelemetry(),
undefined,
"Build ID mismatch false positive count should be undefined"
);
ok(await ensureBuildID(), "System has correct platform.ini");
let profD = Services.dirsvc.get("GreD", Ci.nsIFile);
let platformIniOrig = await IOUtils.readUTF8(
PathUtils.join(profD.path, "platform.ini")
);
await IOUtils.remove(PathUtils.join(profD.path, "platform.ini"));
setBuildidMatchDontSendEnv();
await forceCleanProcesses();
let eventPromise = getEventPromise(
"oop-browser-buildid-mismatch",
"no-platform-ini"
);
let tab = await openNewTab(false);
await eventPromise;
await IOUtils.writeUTF8(
PathUtils.join(profD.path, "platform.ini"),
platformIniOrig,
{ flush: true }
);
unsetBuildidMatchDontSendEnv();
is(
getFalsePositiveTelemetry(),
undefined,
"Build ID mismatch false positive count should be undefined"
);
await closeTab(tab);
});

Просмотреть файл

@ -10,6 +10,13 @@ prefs = [
] ]
# Bug 1876056: remove once bug 1877361 is fixed # Bug 1876056: remove once bug 1877361 is fixed
["browser_aboutRestartRequired_buildid_false-positive.js"] ["browser_aboutRestartRequired_buildid_false-positive.js"]
skip-if = ["win11_2009 && msix && debug"] # bug 1823581 skip-if = ["win11_2009 && msix && debug"] # bug 1823581
# Bug 1888355: re-enable once bug 1877361 is fixed
["browser_aboutRestartRequired_buildid_mismatch.js"]
skip-if = ["win11_2009 && msix && debug"] # bug 1823581
# Bug 1888355: re-enable once bug 1877361 is fixed
["browser_aboutRestartRequired_buildid_no-platform-ini.js"]
skip-if = ["win11_2009 && msix && debug"] # bug 1823581

Просмотреть файл

@ -171,6 +171,15 @@ function getEventPromise(eventName, eventKind) {
}); });
} }
async function ensureBuildID() {
let profD = Services.dirsvc.get("GreD", Ci.nsIFile);
let platformIniOrig = await IOUtils.readUTF8(
PathUtils.join(profD.path, "platform.ini")
);
let buildID = Services.appinfo.platformBuildID;
return platformIniOrig.indexOf(buildID) > 0;
}
async function openNewTab(forceCrash) { async function openNewTab(forceCrash) {
const PAGE = const PAGE =
"data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page."; "data:text/html,<html><body>A%20regular,%20everyday,%20normal%20page.";

Просмотреть файл

@ -600,7 +600,6 @@ LOCAL_INCLUDES += [
"/security/manager/ssl", "/security/manager/ssl",
"/third_party/xsimd/include", "/third_party/xsimd/include",
"/widget", "/widget",
"/xpcom/build",
"/xpcom/ds", "/xpcom/ds",
] ]

Просмотреть файл

@ -130,10 +130,7 @@
#include "mozilla/ContentPrincipal.h" #include "mozilla/ContentPrincipal.h"
#include "buildid_section.h" #include "nsSystemInfo.h"
#include "mozilla/toolkit/library/buildid_reader_ffi.h"
#include "nsXPCOMPrivate.h" // for XUL_DLL
#include "nsXULPopupManager.h" #include "nsXULPopupManager.h"
#ifdef NS_PRINTING #ifdef NS_PRINTING
@ -3660,22 +3657,26 @@ static mozilla::Result<bool, nsresult> BuildIDMismatchMemoryAndDisk() {
} }
#endif #endif
rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(file)); rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file));
MOZ_TRY(rv); MOZ_TRY(rv);
rv = file->Append(XUL_DLL u""_ns); rv = file->AppendNative("platform.ini"_ns);
MOZ_TRY(rv); MOZ_TRY(rv);
nsAutoString xul; nsCOMPtr<nsIINIParserFactory> iniFactory =
rv = file->GetPath(xul); do_GetService("@mozilla.org/xpcom/ini-parser-factory;1", &rv);
MOZ_TRY(rv); MOZ_TRY(rv);
nsCString installedBuildID; nsCOMPtr<nsIINIParser> parser;
nsCString section_name(MOZ_BUILDID_SECTION_NAME); rv = iniFactory->CreateINIParser(file, getter_AddRefs(parser));
rv = read_toolkit_buildid_from_file(&xul, &section_name, &installedBuildID);
MOZ_TRY(rv); MOZ_TRY(rv);
return (installedBuildID != PlatformBuildID()); nsAutoCString installedBuildID;
rv = parser->GetString("Build"_ns, "BuildID"_ns, installedBuildID);
MOZ_TRY(rv);
nsDependentCString runningBuildID(PlatformBuildID());
return (installedBuildID != runningBuildID);
} }
void nsFrameLoader::MaybeNotifyCrashed(BrowsingContext* aBrowsingContext, void nsFrameLoader::MaybeNotifyCrashed(BrowsingContext* aBrowsingContext,

Просмотреть файл

@ -562,6 +562,7 @@ class LinuxArtifactJob(ArtifactJob):
"{product}/{product}-bin", "{product}/{product}-bin",
"{product}/minidump-analyzer", "{product}/minidump-analyzer",
"{product}/pingsender", "{product}/pingsender",
"{product}/platform.ini",
"{product}/plugin-container", "{product}/plugin-container",
"{product}/updater", "{product}/updater",
"{product}/glxtest", "{product}/glxtest",
@ -745,6 +746,7 @@ class MacArtifactJob(ArtifactJob):
"gmp-clearkey/0.1/libclearkey.dylib", "gmp-clearkey/0.1/libclearkey.dylib",
# 'gmp-fake/1.0/libfake.dylib', # 'gmp-fake/1.0/libfake.dylib',
# 'gmp-fakeopenh264/1.0/libfakeopenh264.dylib', # 'gmp-fakeopenh264/1.0/libfakeopenh264.dylib',
"platform.ini",
], ],
) )
] ]
@ -796,6 +798,7 @@ class WinArtifactJob(ArtifactJob):
_package_artifact_patterns = { _package_artifact_patterns = {
"{product}/dependentlibs.list", "{product}/dependentlibs.list",
"{product}/platform.ini",
"{product}/**/*.dll", "{product}/**/*.dll",
"{product}/*.exe", "{product}/*.exe",
"{product}/*.tlb", "{product}/*.tlb",

Просмотреть файл

@ -2148,12 +2148,6 @@ criteria = "safe-to-deploy"
delta = "0.7.1 -> 0.8.0" delta = "0.7.1 -> 0.8.0"
notes = "Fairly straightforward feature improvements." notes = "Fairly straightforward feature improvements."
[[audits.goblin]]
who = "Alexandre Lissy <lissyx+mozillians@lissyx.dyndns.org>"
criteria = "safe-to-deploy"
delta = "0.8.0 -> 0.8.1"
notes = "Updating goblin to 0.8.1 that includes my fix for Elf SectionHeader parsing"
[[audits.gpu-alloc]] [[audits.gpu-alloc]]
who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>" who = "Teodor Tanasoaia <ttanasoaia@mozilla.com>"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"

Просмотреть файл

@ -109,14 +109,6 @@ class RemoteGTests(object):
# TODO -- consider packaging the gtest libxul.so in an apk # TODO -- consider packaging the gtest libxul.so in an apk
self.device.push(libxul_path, self.remote_libdir) self.device.push(libxul_path, self.remote_libdir)
for buildid in ["correct", "broken", "missing"]:
libxul_buildid_name = "libxul_{}_buildid.so".format(buildid)
libxul_buildid_path = os.path.join(
os.path.dirname(libxul_path), libxul_buildid_name
)
if os.path.isfile(libxul_buildid_path):
self.device.push(libxul_buildid_path, self.remote_libdir)
# Push support files to device. Avoid sub-directories so that libxul.so # Push support files to device. Avoid sub-directories so that libxul.so
# is not included. # is not included.
for f in glob.glob(os.path.join(test_dir, "*")): for f in glob.glob(os.path.join(test_dir, "*")):

Просмотреть файл

@ -213,7 +213,6 @@ ifdef STRIP_COMPILED_TESTS
else else
cp -RL $(DIST)/bin/gtest $(PKG_STAGE)/gtest/gtest_bin cp -RL $(DIST)/bin/gtest $(PKG_STAGE)/gtest/gtest_bin
endif endif
cp -RL $(DIST)/bin/gtest/*buildid.* $(PKG_STAGE)/gtest/gtest_bin/gtest
cp -RL $(DEPTH)/_tests/gtest $(PKG_STAGE) cp -RL $(DEPTH)/_tests/gtest $(PKG_STAGE)
cp $(topsrcdir)/testing/gtest/rungtests.py $(PKG_STAGE)/gtest cp $(topsrcdir)/testing/gtest/rungtests.py $(PKG_STAGE)/gtest
cp $(topsrcdir)/testing/gtest/remotegtests.py $(PKG_STAGE)/gtest cp $(topsrcdir)/testing/gtest/remotegtests.py $(PKG_STAGE)/gtest

Просмотреть файл

@ -1 +1 @@
{"files":{"CHANGELOG.md":"50453c2109df5663c2e96b8f1f23525249c5fc2f59c8f74ec5c2b3646ac21144","Cargo.toml":"5a5859d8a4040b75bbceda8bca57dae75a4b61d28dce36aede2808e6b086c6f8","LICENSE":"655e3ee7a4c27430774962e62a6d37d7348e5f2f292010ad674ce1bebefd24bc","README.md":"5791f3dd86bcb4de9b580abf27ca6a9f59e03e87f35262c9fab2baf4b07bf930","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"2837231dd3e2341008842e031b81cbb9999214a2f9e6738c6374a5464d62555d","src/elf/dynamic.rs":"907146d1968f656fc9cc3621037c193877e30675ccd8ec6eb2e3adbc1e2afd27","src/elf/gnu_hash.rs":"4592b5516d807a61a9dccc3f97266587c032eea621708bd78e23c70be6128228","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"e952fc4f79ac6a08f218a4758321ab94f172c376dc5235a82f70732682cca82f","src/elf/section_header.rs":"72eb788e8807f16a97683d20add21d5c3feaae06813509e2a87b76a7cd0c376f","src/elf/sym.rs":"267996f926f337b88058908af260be30473afbe1fe6d72cdeb8dd0ed474671d8","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"a1bb56d82db52ac627e55b163f489f06a78c939a8ccfdec210b4f726d6ed6e9d","src/lib.rs":"06771b56b262fa30396e4bacbf0a4996b6088d1cfa5defa20dedf69a2c58d3b3","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"42e6f0973092185db233230e71e9312bbac7c2e1090bb6d713804020319dfa33","src/mach/mod.rs":"f1e120b7aabe370fa2af43e359f97ffa3e187fdb5743ef19c37402264e92b326","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"947acd8a724b41d0afbbd9e2727f41be51f1be439f47417258e829db1a4765e6","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"36b5b3ddc9806f679cf21418bc13af4b277eba87096304dfb50946bc0f941206","src/pe/certificate_table.rs":"f6c31ba518d9fc4b6e12d2f24d6c9d58b21b341a1f189cbcf2aae0ae51304ad3","src/pe/characteristic.rs":"2ffa012ec225f3c8570689713969a7dc34a92eaf4f944a27881fd0c248cc8b20","src/pe/data_directories.rs":"d0352ccc03e0ab2935235e91b391cc55828406087f026f90ec11ca5906fd8c8c","src/pe/debug.rs":"4b570730d674239ba6f9f7b6bb889206c463bce91a1a0cf84d4f519e0735ee8c","src/pe/dll_characteristic.rs":"d63e86ecb38ccdd81493268be34535391b794651d619e8d4ccc1a56aa10e1679","src/pe/exception.rs":"3935900334692a6f54f7176eca044688289834bcde1b579b88d6ed1af3c3c005","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"5bf09980c4113c7572010e6c5a356ace1a65a11203c0aa69a6d1f38be9c9d471","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"6d2dc2c555e5802687dfe46b70c8200a1e83dd67eaed4c4cc7979cb5f6890755","src/pe/optional_header.rs":"f2411a0f272e22c280a1fe3c15919b07d1f152448b47db31acaacad8a0a9a153","src/pe/options.rs":"457877197f768c331437297d787dc718b1053b813e3a1dd9b968133fb1540d44","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"e4b1a2f78c2336aaa0355b5ef102dbe29138c4fa1ba29ed3f379aad1fc64bdff","src/pe/subsystem.rs":"162a851e217b617aa8afa1b83e37ea9c5a793f76a17be57b56b550d7cabb7b8a","src/pe/symbol.rs":"1a5fb5bec5727752a6506682ed2ab57829ea810f21f951932a0107861ec0e092","src/pe/utils.rs":"e6da9979ba5f2ae7d1274eef8230cdc4dd90c90a79c7bb9438f8b8ff0aef74be","src/strtab.rs":"110c774b2998514b4d0be1d575b3e2a8eb85f801b6f782e4ed3a8f7521920689","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9","tests/bins/te/README.md":"a0daf347449bcf82c38d981b2a700d9fd4657c3a7e7dbfa22f90e74750c6bc0d"},"package":"8ce2dfb858618fd40cafc83efadd02705adf6ffba765098736bd950c3c945fe0"} {"files":{"CHANGELOG.md":"2d45bc2d0db50fd4416e2123f8b98c7288935b3be7985bdd115ecbd236acea41","Cargo.toml":"0d8dade295950e9f63574e7a74390ddec56c039cb44d2507df7e6ff832b49a0d","LICENSE":"036bf6b6d6fd6dd1abda2ff6cdb672a63bdf32c468048720072910f2268a965f","README.md":"302466b411dc5bc705cdf563b928c14755342ab6f2dff371be064446fa0aa0a9","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"a010071cd2a25ab71e0c7181eb1d9f417daa2d1ec25a09c74bd12ad944892225","src/elf/dynamic.rs":"c26e75311f2da9e34dc4c0a2120dfcc20df88a41d67c52b9bf703258de018fd8","src/elf/gnu_hash.rs":"7a9fcaf6cb38167d20527364bdf9bc2379c44dede5d7666275a1eb20dc665179","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"a5d21f9d1ddae8e730e852fcaf1cd2dd194e35fbac8f86fb8fd9033a03bdc66d","src/elf/section_header.rs":"f55f4d263f618bd1dec76ff0483f3b2dc3791c8e5c5c2b6ff296a5bc26001666","src/elf/sym.rs":"045c01107f4e100d6827cb819b82a28ea10c0d9bc00a1cdddb04a0865f1162ec","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"a1bb56d82db52ac627e55b163f489f06a78c939a8ccfdec210b4f726d6ed6e9d","src/lib.rs":"f29832bdf7d7f7d9e34f65704afea2710d578df60cc171dd179b5ce889faaf12","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"42e6f0973092185db233230e71e9312bbac7c2e1090bb6d713804020319dfa33","src/mach/mod.rs":"53ad219fd2265a5689ab38d5031722268eab6bbb649c75756e74295df4b611b7","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"0dc29bf42b25f60c7258bc8b757f6a862e846582dd6d2e70737933ad6334a0e4","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"ad9c77e42392b49114cf8ce2839111f3231dcfe21cbb8e402ee14e568f5ae657","src/pe/certificate_table.rs":"f6c31ba518d9fc4b6e12d2f24d6c9d58b21b341a1f189cbcf2aae0ae51304ad3","src/pe/characteristic.rs":"6f810a6e5646b922cf7e3ca6d314677a4e1e1ad5695278c2b1b527a05f4299f3","src/pe/data_directories.rs":"d0352ccc03e0ab2935235e91b391cc55828406087f026f90ec11ca5906fd8c8c","src/pe/debug.rs":"3811c616a9b6d6b54e15348bb369b794bb89532e04fe19eca91b745d7c51a553","src/pe/exception.rs":"de2c9c07812ecd315c8400fc8fdcadc6a44d7a8be96e69a3f4ccf14ef8cf8426","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"879c2ddc8318ab37b4577ac34241fa039d106e0e530dab07edfc9b4e13b08356","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"ffaeca313ea2fb31c41eb0ede0ef28fede2276b0bb7d81dfc08b4ead6289600d","src/pe/optional_header.rs":"4048151649a7fe3f8f2d7bb67e784bae889eeb1651bf924f9fbe92400b809217","src/pe/options.rs":"457877197f768c331437297d787dc718b1053b813e3a1dd9b968133fb1540d44","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"e4b1a2f78c2336aaa0355b5ef102dbe29138c4fa1ba29ed3f379aad1fc64bdff","src/pe/symbol.rs":"1a5fb5bec5727752a6506682ed2ab57829ea810f21f951932a0107861ec0e092","src/pe/utils.rs":"e6da9979ba5f2ae7d1274eef8230cdc4dd90c90a79c7bb9438f8b8ff0aef74be","src/strtab.rs":"dcbd0592c7f032980d112a5f752c175fe8dd257a948892e1f060d25ab52328f5","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9"},"package":"bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887"}

14
third_party/rust/goblin/CHANGELOG.md поставляемый
Просмотреть файл

@ -5,20 +5,6 @@ Before 1.0, this project does not adhere to [Semantic Versioning](http://semver.
Goblin is now 0.8, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97 Goblin is now 0.8, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97
## [0.8.1] - 2024-04-27
### Docs
pe: document pe header, thanks @JohnScience: https://github.com/m4b/goblin/pull/399
pe, elf: fix doc warnings, thanks @5225225: https://github.com/m4b/goblin/pull/395
pe: document dos header, thanks @JohnScience: https://github.com/m4b/goblin/pull/393
### Added
pe: add TE (terse executable) support, big thanks @Javagedes: https://github.com/m4b/goblin/pull/397
elf: allow parsing section headers from raw bytes, thanks @lissyx: https://github.com/m4b/goblin/pull/391
mach: add support for lossy parsing, thanks @h33p: https://github.com/m4b/goblin/pull/386
elf: add convenience functions, thanks @tiann : https://github.com/m4b/goblin/pull/387
### Fixed
pe: read reserved dos headers, thanks @kkent030315: https://github.com/m4b/goblin/pull/405
## [0.8.0] - 2023-12-31 - Happy New Years! ## [0.8.0] - 2023-12-31 - Happy New Years!
### Breaking ### Breaking
msrv: bumped to 1.63.0 since scroll bumped as well msrv: bumped to 1.63.0 since scroll bumped as well

8
third_party/rust/goblin/Cargo.toml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@
edition = "2021" edition = "2021"
rust-version = "1.63.0" rust-version = "1.63.0"
name = "goblin" name = "goblin"
version = "0.8.1" version = "0.8.0"
authors = [ authors = [
"m4b <m4b.github.io@gmail.com>", "m4b <m4b.github.io@gmail.com>",
"seu <seu@panopticon.re>", "seu <seu@panopticon.re>",
@ -44,6 +44,7 @@ categories = [
] ]
license = "MIT" license = "MIT"
repository = "https://github.com/m4b/goblin" repository = "https://github.com/m4b/goblin"
resolver = "2"
[dependencies.log] [dependencies.log]
version = "0.4" version = "0.4"
@ -74,7 +75,6 @@ default = [
"mach64", "mach64",
"pe32", "pe32",
"pe64", "pe64",
"te",
"archive", "archive",
"endian_fd", "endian_fd",
] ]
@ -103,10 +103,6 @@ std = [
"alloc", "alloc",
"scroll/std", "scroll/std",
] ]
te = [
"alloc",
"endian_fd",
]
[badges.travis-ci] [badges.travis-ci]
branch = "master" branch = "master"

2
third_party/rust/goblin/LICENSE поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) m4b 2016-2024 Copyright (c) m4b 2016-2018
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

17
third_party/rust/goblin/README.md поставляемый
Просмотреть файл

@ -97,7 +97,6 @@ Here are some things you could do with this crate (or help to implement so they
* mach32 - 32-bit mach-o `repr(C)` struct defs * mach32 - 32-bit mach-o `repr(C)` struct defs
* pe32 - 32-bit PE `repr(C)` struct defs * pe32 - 32-bit PE `repr(C)` struct defs
* pe64 - 64-bit PE `repr(C)` struct defs * pe64 - 64-bit PE `repr(C)` struct defs
+ te - Terse Executable (TE) `repr(C)` struct defs
* archive - a Unix Archive parser * archive - a Unix Archive parser
* endian_fd - parses according to the endianness in the binary * endian_fd - parses according to the endianness in the binary
* std - to allow `no_std` environments * std - to allow `no_std` environments
@ -109,7 +108,6 @@ Thank you all :heart: !
In lexicographic order: In lexicographic order:
- [@2vg] - [@2vg]
- [@5225225]
- [@alessandrod] - [@alessandrod]
- [@amanieu] - [@amanieu]
- [@anfedotoff] - [@anfedotoff]
@ -123,26 +121,21 @@ In lexicographic order:
- [@ExPixel] - [@ExPixel]
- [@flanfly] - [@flanfly]
- [@glandium] - [@glandium]
- [@h33p]
- [@ibabushkin] - [@ibabushkin]
- [@jackcmay] - [@jackcmay]
- [@jan-auer] - [@jan-auer]
- [@Javagedes]
- [@jessehui] - [@jessehui]
- [@jdub] - [@jdub]
- [@Jhynjhiruu] - [@Jhynjhiruu]
- [@johannst] - [@johannst]
- [@JohnScience]
- [@jrmuizel] - [@jrmuizel]
- [@jsgf] - [@jsgf]
- [@keith] - [@keith]
- [@kjempelodott] - [@kjempelodott]
- [@kkent030315]
- [@ko1n] - [@ko1n]
- [@le-jzr] - [@le-jzr]
- [@Lichtso] - [@Lichtso]
- [@lion128] - [@lion128]
- [@lissyx]
- [@llogiq] - [@llogiq]
- [@lumag] - [@lumag]
- [@lzutao] - [@lzutao]
@ -175,7 +168,6 @@ In lexicographic order:
- [@SquareMan] - [@SquareMan]
- [@tathanhdinh] - [@tathanhdinh]
- [@Techno-coder] - [@Techno-coder]
- [@tiann]
- [@ticki] - [@ticki]
- [@Timmmm] - [@Timmmm]
- [@Tiwalun] - [@Tiwalun]
@ -191,7 +183,6 @@ In lexicographic order:
<!-- Contributors --> <!-- Contributors -->
[@2vg]: https://github.com/2vg [@2vg]: https://github.com/2vg
[@5225225]: https://github.com/5225225
[@alessandrod]: https://github.com/alessandrod [@alessandrod]: https://github.com/alessandrod
[@amanieu]: https://github.com/amanieu [@amanieu]: https://github.com/amanieu
[@anfedotoff]: https://github.com/anfedotoff [@anfedotoff]: https://github.com/anfedotoff
@ -206,26 +197,21 @@ In lexicographic order:
[@ExPixel]: https://github.com/ExPixel [@ExPixel]: https://github.com/ExPixel
[@flanfly]: https://github.com/flanfly [@flanfly]: https://github.com/flanfly
[@glandium]: https://github.com/glandium [@glandium]: https://github.com/glandium
[@h33p]: https://github.com/h33p
[@ibabushkin]: https://github.com/ibabushkin [@ibabushkin]: https://github.com/ibabushkin
[@jackcmay]: https://github.com/jackcmay [@jackcmay]: https://github.com/jackcmay
[@jan-auer]: https://github.com/jan-auer [@jan-auer]: https://github.com/jan-auer
[@Javagedes]: https://github.com/Javagedes
[@jessehui]: https://github.com/jessehui [@jessehui]: https://github.com/jessehui
[@Jhynjhiruu]: https://github.com/Jhynjhiruu [@Jhynjhiruu]: https://github.com/Jhynjhiruu
[@JohnScience]: https://github.com/JohnScience
[@johannst]: https://github.com/johannst [@johannst]: https://github.com/johannst
[@jdub]: https://github.com/jdub [@jdub]: https://github.com/jdub
[@jrmuizel]: https://github.com/jrmuizel [@jrmuizel]: https://github.com/jrmuizel
[@jsgf]: https://github.com/jsgf [@jsgf]: https://github.com/jsgf
[@keith]: https://github.com/keith [@keith]: https://github.com/keith
[@kjempelodott]: https://github.com/kjempelodott [@kjempelodott]: https://github.com/kjempelodott
[@kkent030315]: https://github.com/kkent030315
[@ko1N]: https://github.com/ko1N [@ko1N]: https://github.com/ko1N
[@le-jzr]: https://github.com/le-jzr [@le-jzr]: https://github.com/le-jzr
[@Lichtso]: https://github.com/Lichtso [@Lichtso]: https://github.com/Lichtso
[@lion128]: https://github.com/lion128 [@lion128]: https://github.com/lion128
[@lissyx]: https://github.com/lissyx
[@llogiq]: https://github.com/llogiq [@llogiq]: https://github.com/llogiq
[@lumag]: https://github.com/lumag [@lumag]: https://github.com/lumag
[@lzutao]: https://github.com/lzutao [@lzutao]: https://github.com/lzutao
@ -259,7 +245,6 @@ In lexicographic order:
[@SquareMan]: https://github.com/SquareMan [@SquareMan]: https://github.com/SquareMan
[@tathanhdinh]: https://github.com/tathanhdinh [@tathanhdinh]: https://github.com/tathanhdinh
[@Techno-coder]: https://github.com/Techno-coder [@Techno-coder]: https://github.com/Techno-coder
[@tiann]: https://github.com/tiann
[@ticki]: https://github.com/ticki [@ticki]: https://github.com/ticki
[@Timmmm]: https://github.com/Timmmm [@Timmmm]: https://github.com/Timmmm
[@Tiwalun]: https://github.com/Tiwalun [@Tiwalun]: https://github.com/Tiwalun
@ -275,8 +260,6 @@ In lexicographic order:
## Contributing ## Contributing
Unless explicitly stated otherwise, you agree that your contributions are licensed as described in the accompanying LICENSE file (MIT).
1. Please prefix commits with the affected binary component; the more specific the better, e.g., 1. Please prefix commits with the affected binary component; the more specific the better, e.g.,
if you only modify relocations in the elf module, then do "elf.reloc: added new constants for Z80" if you only modify relocations in the elf module, then do "elf.reloc: added new constants for Z80"
1. Commit messages must explain their change, no generic "changed", or "fix"; if you push commits 1. Commit messages must explain their change, no generic "changed", or "fix"; if you push commits

Просмотреть файл

@ -498,7 +498,7 @@ pub const R_ARM_GOT32: u32 = 26;
pub const R_ARM_PLT32: u32 = 27; pub const R_ARM_PLT32: u32 = 27;
/// PC relative 24 bit (BL, BLX) /// PC relative 24 bit (BL, BLX)
pub const R_ARM_CALL: u32 = 28; pub const R_ARM_CALL: u32 = 28;
/// PC relative 24 bit (B, BL&lt;cond&gt;) /// PC relative 24 bit (B, BL<cond>)
pub const R_ARM_JUMP24: u32 = 29; pub const R_ARM_JUMP24: u32 = 29;
/// PC relative 24 bit (Thumb32 B.W) /// PC relative 24 bit (Thumb32 B.W)
pub const R_ARM_THM_JUMP24: u32 = 30; pub const R_ARM_THM_JUMP24: u32 = 30;
@ -539,7 +539,7 @@ pub const R_ARM_THM_MOVT_ABS: u32 = 48;
pub const R_ARM_THM_MOVW_PREL_NC: u32 = 49; pub const R_ARM_THM_MOVW_PREL_NC: u32 = 49;
/// PC relative high 16 bit (Thumb32 MOVT) /// PC relative high 16 bit (Thumb32 MOVT)
pub const R_ARM_THM_MOVT_PREL: u32 = 50; pub const R_ARM_THM_MOVT_PREL: u32 = 50;
/// PC relative 20 bit (Thumb32 B&lt;cond&gt;.W) /// PC relative 20 bit (Thumb32 B<cond>.W)
pub const R_ARM_THM_JUMP19: u32 = 51; pub const R_ARM_THM_JUMP19: u32 = 51;
/// PC relative X & 0x7E (Thumb16 CBZ, CBNZ) /// PC relative X & 0x7E (Thumb16 CBZ, CBNZ)
pub const R_ARM_THM_JUMP6: u32 = 52; pub const R_ARM_THM_JUMP6: u32 = 52;
@ -636,7 +636,7 @@ pub const R_ARM_GNU_VTENTRY: u32 = 100;
pub const R_ARM_GNU_VTINHERIT: u32 = 101; pub const R_ARM_GNU_VTINHERIT: u32 = 101;
/// PC relative & 0xFFE (Thumb16 B) /// PC relative & 0xFFE (Thumb16 B)
pub const R_ARM_THM_PC11: u32 = 102; pub const R_ARM_THM_PC11: u32 = 102;
/// PC relative & 0x1FE (Thumb16 B/B&lt;cond&gt;) /// PC relative & 0x1FE (Thumb16 B/B<cond>)
pub const R_ARM_THM_PC9: u32 = 103; pub const R_ARM_THM_PC9: u32 = 103;
/// PC-rel 32 bit for global dynamic thread local data /// PC-rel 32 bit for global dynamic thread local data
pub const R_ARM_TLS_GD32: u32 = 104; pub const R_ARM_TLS_GD32: u32 = 104;

2
third_party/rust/goblin/src/elf/dynamic.rs поставляемый
Просмотреть файл

@ -550,7 +550,7 @@ macro_rules! elf_dyn_std_impl {
} }
// TODO: these bare functions have always seemed awkward, but not sure where they should go... // TODO: these bare functions have always seemed awkward, but not sure where they should go...
/// Maybe gets and returns the dynamic array with the same lifetime as the `phdrs`, using the provided bias with wrapping addition. /// Maybe gets and returns the dynamic array with the same lifetime as the [phdrs], using the provided bias with wrapping addition.
/// If the bias is wrong, it will either segfault or give you incorrect values, beware /// If the bias is wrong, it will either segfault or give you incorrect values, beware
pub unsafe fn from_phdrs(bias: usize, phdrs: &[$phdr]) -> Option<&[Dyn]> { pub unsafe fn from_phdrs(bias: usize, phdrs: &[$phdr]) -> Option<&[Dyn]> {
for phdr in phdrs { for phdr in phdrs {

6
third_party/rust/goblin/src/elf/gnu_hash.rs поставляемый
Просмотреть файл

@ -13,9 +13,9 @@
//! 4. shift2 //! 4. shift2
//! //!
//! See more: //! See more:
//! * <http://www.linker-aliens.org/blogs/ali/entry/gnu_hash_elf_sections> //! * http://www.linker-aliens.org/blogs/ali/entry/gnu_hash_elf_sections
//! or <https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2> //! or https://blogs.oracle.com/solaris/gnu-hash-elf-sections-v2
//! * <https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/> //! * https://flapenguin.me/2017/05/10/elf-lookup-dt-gnu-hash/
/// GNU hash function: accepts a symbol name and returns a value that may be /// GNU hash function: accepts a symbol name and returns a value that may be
/// used to compute a bucket index. /// used to compute a bucket index.

6
third_party/rust/goblin/src/elf/reloc.rs поставляемый
Просмотреть файл

@ -56,14 +56,14 @@
//! | `R_X86_64_TLSDESC` | 36 | 64 × 2 | | //! | `R_X86_64_TLSDESC` | 36 | 64 × 2 | |
//! | `R_X86_64_IRELATIVE` | 37 | 64 | indirect (B + A) | //! | `R_X86_64_IRELATIVE` | 37 | 64 | indirect (B + A) |
//! //!
//! TLS information is at <http://people.redhat.com/aoliva/writeups/TLS/RFC-TLSDESC-x86.txt> //! TLS information is at http://people.redhat.com/aoliva/writeups/TLS/RFC-TLSDESC-x86.txt
//! //!
//! `R_X86_64_IRELATIVE` is similar to `R_X86_64_RELATIVE` except that //! `R_X86_64_IRELATIVE` is similar to `R_X86_64_RELATIVE` except that
//! the value used in this relocation is the program address returned by the function, //! the value used in this relocation is the program address returned by the function,
//! which takes no arguments, at the address of the result of the corresponding //! which takes no arguments, at the address of the result of the corresponding
//! `R_X86_64_RELATIVE` relocation. //! `R_X86_64_RELATIVE` relocation.
//! //!
//! Read more <https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html> //! Read more https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html
include!("constants_relocation.rs"); include!("constants_relocation.rs");
@ -129,6 +129,8 @@ macro_rules! elf_reloc {
macro_rules! elf_rela_std_impl { macro_rules! elf_rela_std_impl {
($size:ident, $isize:ty) => { ($size:ident, $isize:ty) => {
if_alloc! { if_alloc! {
use crate::elf::reloc::Reloc;
use core::slice; use core::slice;
if_std! { if_std! {

Просмотреть файл

@ -406,7 +406,7 @@ if_alloc! {
} }
impl SectionHeader { impl SectionHeader {
/// Return the size of the underlying section header, given a `Ctx` /// Return the size of the underlying program header, given a `container`
#[inline] #[inline]
pub fn size(ctx: Ctx) -> usize { pub fn size(ctx: Ctx) -> usize {
use scroll::ctx::SizeWith; use scroll::ctx::SizeWith;
@ -442,25 +442,18 @@ if_alloc! {
self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize) self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize)
} }
/// Parse `count` section headers from `bytes` at `offset`, using the given `ctx` /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx`
/// Assuming this is read from the whole file, it will check offset.
#[cfg(feature = "endian_fd")] #[cfg(feature = "endian_fd")]
pub fn parse(bytes: &[u8], offset: usize, count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> { pub fn parse(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
use scroll::Pread;
// Zero offset means no section headers, not even the null section header. // Zero offset means no section headers, not even the null section header.
if offset == 0 { if offset == 0 {
return Ok(Vec::new()); return Ok(Vec::new());
} }
Self::parse_from(bytes, offset, count, ctx)
}
/// Parse `count` section headers from `bytes` at `offset`, using the given `ctx`
/// without performing any offset checking to allow parsing relatively
#[cfg(feature = "endian_fd")]
pub fn parse_from(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
use scroll::Pread;
let empty_sh = bytes.gread_with::<SectionHeader>(&mut offset, ctx)?; let empty_sh = bytes.gread_with::<SectionHeader>(&mut offset, ctx)?;
if count == 0 as usize { if count == 0 as usize {
// Zero count means either no section headers or the number of section headers // Zero count means either no section headers if offset is also zero (checked
// overflows SHN_LORESERVE, in which case the count is stored in the sh_size field // above), or the number of section headers overflows SHN_LORESERVE, in which
// of the null section header. // case the count is stored in the sh_size field of the null section header.
count = empty_sh.sh_size as usize; count = empty_sh.sh_size as usize;
} }

12
third_party/rust/goblin/src/elf/sym.rs поставляемый
Просмотреть файл

@ -541,18 +541,6 @@ if_alloc! {
self.count self.count
} }
/// The offset of symbol table in elf
#[inline]
pub fn offset(&self) -> usize {
self.start
}
/// The ctx of symbol table
#[inline]
pub fn ctx(&self) -> &Ctx {
&self.ctx
}
/// Returns true if table has no symbols. /// Returns true if table has no symbols.
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {

7
third_party/rust/goblin/src/lib.rs поставляемый
Просмотреть файл

@ -229,7 +229,6 @@ pub enum Hint {
Mach(HintData), Mach(HintData),
MachFat(usize), MachFat(usize),
PE, PE,
TE,
COFF, COFF,
Archive, Archive,
Unknown(u64), Unknown(u64),
@ -237,7 +236,7 @@ pub enum Hint {
macro_rules! if_everything { macro_rules! if_everything {
($($i:item)*) => ($( ($($i:item)*) => ($(
#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "te", feature = "mach64", feature = "mach32", feature = "archive"))] #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))]
$i $i
)*) )*)
} }
@ -263,7 +262,6 @@ if_everything! {
} else { } else {
match *&bytes[0..2].pread_with::<u16>(0, LE)? { match *&bytes[0..2].pread_with::<u16>(0, LE)? {
pe::header::DOS_MAGIC => Ok(Hint::PE), pe::header::DOS_MAGIC => Ok(Hint::PE),
pe::header::TE_MAGIC => Ok(Hint::TE),
pe::header::COFF_MACHINE_X86 | pe::header::COFF_MACHINE_X86 |
pe::header::COFF_MACHINE_X86_64 | pe::header::COFF_MACHINE_X86_64 |
pe::header::COFF_MACHINE_ARM64 => Ok(Hint::COFF), pe::header::COFF_MACHINE_ARM64 => Ok(Hint::COFF),
@ -292,8 +290,6 @@ if_everything! {
Elf(elf::Elf<'a>), Elf(elf::Elf<'a>),
/// A PE32/PE32+! /// A PE32/PE32+!
PE(pe::PE<'a>), PE(pe::PE<'a>),
/// A TE!
TE(pe::TE<'a>),
/// A COFF /// A COFF
COFF(pe::Coff<'a>), COFF(pe::Coff<'a>),
/// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container! /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container!
@ -313,7 +309,6 @@ if_everything! {
Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)), Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)),
Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)), Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)),
Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)), Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)),
Hint::TE => Ok(Object::TE(pe::TE::parse(bytes)?)),
Hint::COFF => Ok(Object::COFF(pe::Coff::parse(bytes)?)), Hint::COFF => Ok(Object::COFF(pe::Coff::parse(bytes)?)),
Hint::Unknown(magic) => Ok(Object::Unknown(magic)), Hint::Unknown(magic) => Ok(Object::Unknown(magic)),
} }

76
third_party/rust/goblin/src/mach/mod.rs поставляемый
Просмотреть файл

@ -147,17 +147,7 @@ impl<'a> MachO<'a> {
} }
} }
/// Parses the Mach-o binary from `bytes` at `offset` /// Parses the Mach-o binary from `bytes` at `offset`
pub fn parse(bytes: &'a [u8], offset: usize) -> error::Result<MachO<'a>> { pub fn parse(bytes: &'a [u8], mut offset: usize) -> error::Result<MachO<'a>> {
Self::parse_impl(bytes, offset, false)
}
/// Parses the Mach-o binary from `bytes` at `offset` in lossy mode
pub fn parse_lossy(bytes: &'a [u8], offset: usize) -> error::Result<MachO<'a>> {
Self::parse_impl(bytes, offset, true)
}
/// Parses the Mach-o binary from `bytes` at `offset` in `lossy` mode
fn parse_impl(bytes: &'a [u8], mut offset: usize, lossy: bool) -> error::Result<MachO<'a>> {
let (magic, maybe_ctx) = parse_magic_and_ctx(bytes, offset)?; let (magic, maybe_ctx) = parse_magic_and_ctx(bytes, offset)?;
let ctx = if let Some(ctx) = maybe_ctx { let ctx = if let Some(ctx) = maybe_ctx {
ctx ctx
@ -193,42 +183,27 @@ impl<'a> MachO<'a> {
let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?; let cmd = load_command::LoadCommand::parse(bytes, offset, ctx.le)?;
debug!("{} - {:?}", i, cmd); debug!("{} - {:?}", i, cmd);
match cmd.command { match cmd.command {
load_command::CommandVariant::Segment32(command) => segments.push( load_command::CommandVariant::Segment32(command) => {
segment::Segment::from_32_impl(bytes, &command, cmd.offset, ctx, lossy)?, // FIXME: we may want to be less strict about failure here, and just return an empty segment to allow parsing to continue?
), segments.push(segment::Segment::from_32(bytes, &command, cmd.offset, ctx)?)
load_command::CommandVariant::Segment64(command) => segments.push( }
segment::Segment::from_64_impl(bytes, &command, cmd.offset, ctx, lossy)?, load_command::CommandVariant::Segment64(command) => {
), segments.push(segment::Segment::from_64(bytes, &command, cmd.offset, ctx)?)
}
load_command::CommandVariant::Symtab(command) => { load_command::CommandVariant::Symtab(command) => {
match symbols::Symbols::parse(bytes, &command, ctx) { symbols = Some(symbols::Symbols::parse(bytes, &command, ctx)?);
Ok(s) => symbols = Some(s),
Err(e) if lossy => {
debug!("CommandVariant::Symtab failed: {e}");
}
Err(e) => return Err(e),
}
} }
load_command::CommandVariant::LoadDylib(command) load_command::CommandVariant::LoadDylib(command)
| load_command::CommandVariant::LoadUpwardDylib(command) | load_command::CommandVariant::LoadUpwardDylib(command)
| load_command::CommandVariant::ReexportDylib(command) | load_command::CommandVariant::ReexportDylib(command)
| load_command::CommandVariant::LoadWeakDylib(command) | load_command::CommandVariant::LoadWeakDylib(command)
| load_command::CommandVariant::LazyLoadDylib(command) => { | load_command::CommandVariant::LazyLoadDylib(command) => {
match bytes.pread::<&str>(cmd.offset + command.dylib.name as usize) { let lib = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
Ok(lib) => libs.push(lib), libs.push(lib);
Err(e) if lossy => {
debug!("CommandVariant::Load/Reexport Dylib failed: {e}");
}
Err(e) => return Err(e.into()),
}
} }
load_command::CommandVariant::Rpath(command) => { load_command::CommandVariant::Rpath(command) => {
match bytes.pread::<&str>(cmd.offset + command.path as usize) { let rpath = bytes.pread::<&str>(cmd.offset + command.path as usize)?;
Ok(rpath) => rpaths.push(rpath), rpaths.push(rpath);
Err(e) if lossy => {
debug!("CommandVariant::Rpath failed: {e}");
}
Err(e) => return Err(e.into()),
}
} }
load_command::CommandVariant::DyldInfo(command) load_command::CommandVariant::DyldInfo(command)
| load_command::CommandVariant::DyldInfoOnly(command) => { | load_command::CommandVariant::DyldInfoOnly(command) => {
@ -254,16 +229,9 @@ impl<'a> MachO<'a> {
} }
} }
load_command::CommandVariant::IdDylib(command) => { load_command::CommandVariant::IdDylib(command) => {
match bytes.pread::<&str>(cmd.offset + command.dylib.name as usize) { let id = bytes.pread::<&str>(cmd.offset + command.dylib.name as usize)?;
Ok(id) => { libs[0] = id;
libs[0] = id; name = Some(id);
name = Some(id);
}
Err(e) if lossy => {
debug!("CommandVariant::IdDylib failed: {e}");
}
Err(e) => return Err(e.into()),
}
} }
_ => (), _ => (),
} }
@ -534,16 +502,6 @@ pub enum Mach<'a> {
impl<'a> Mach<'a> { impl<'a> Mach<'a> {
/// Parse from `bytes` either a multi-arch binary or a regular mach-o binary /// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
pub fn parse(bytes: &'a [u8]) -> error::Result<Self> { pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
Self::parse_impl(bytes, false)
}
/// Parse from `bytes` either a multi-arch binary or a regular mach-o binary in lossy mode
pub fn parse_lossy(bytes: &'a [u8]) -> error::Result<Self> {
Self::parse_impl(bytes, true)
}
/// Parse from `bytes` either a multi-arch binary or a regular mach-o binary
fn parse_impl(bytes: &'a [u8], lossy: bool) -> error::Result<Self> {
let size = bytes.len(); let size = bytes.len();
if size < 4 { if size < 4 {
let error = error::Error::Malformed("size is smaller than a magical number".into()); let error = error::Error::Malformed("size is smaller than a magical number".into());
@ -557,7 +515,7 @@ impl<'a> Mach<'a> {
} }
// we might be a regular binary // we might be a regular binary
_ => { _ => {
let binary = MachO::parse_impl(bytes, 0, lossy)?; let binary = MachO::parse(bytes, 0)?;
Ok(Mach::Binary(binary)) Ok(Mach::Binary(binary))
} }
} }

55
third_party/rust/goblin/src/mach/segment.rs поставляемый
Просмотреть файл

@ -466,26 +466,6 @@ impl<'a> Segment<'a> {
segment: &SegmentCommand32, segment: &SegmentCommand32,
offset: usize, offset: usize,
ctx: container::Ctx, ctx: container::Ctx,
) -> Result<Self, error::Error> {
Self::from_32_impl(bytes, segment, offset, ctx, false)
}
/// Convert the raw C 32-bit segment command to a generalized version
pub fn from_32_lossy(
bytes: &'a [u8],
segment: &SegmentCommand32,
offset: usize,
ctx: container::Ctx,
) -> Result<Self, error::Error> {
Self::from_32_impl(bytes, segment, offset, ctx, true)
}
pub(crate) fn from_32_impl(
bytes: &'a [u8],
segment: &SegmentCommand32,
offset: usize,
ctx: container::Ctx,
lossy: bool,
) -> Result<Self, error::Error> { ) -> Result<Self, error::Error> {
Ok(Segment { Ok(Segment {
cmd: segment.cmd, cmd: segment.cmd,
@ -499,47 +479,22 @@ impl<'a> Segment<'a> {
initprot: segment.initprot, initprot: segment.initprot,
nsects: segment.nsects, nsects: segment.nsects,
flags: segment.flags, flags: segment.flags,
data: match segment_data( data: segment_data(
bytes, bytes,
u64::from(segment.fileoff), u64::from(segment.fileoff),
u64::from(segment.filesize), u64::from(segment.filesize),
) { )?,
Ok(v) => v,
Err(_) if lossy => &[],
Err(e) => return Err(e),
},
offset, offset,
raw_data: bytes, raw_data: bytes,
ctx, ctx,
}) })
} }
/// Convert the raw C 64-bit segment command to a generalized version /// Convert the raw C 64-bit segment command to a generalized version
pub fn from_64( pub fn from_64(
bytes: &'a [u8], bytes: &'a [u8],
segment: &SegmentCommand64, segment: &SegmentCommand64,
offset: usize, offset: usize,
ctx: container::Ctx, ctx: container::Ctx,
) -> Result<Self, error::Error> {
Self::from_64_impl(bytes, segment, offset, ctx, false)
}
/// Convert the raw C 64-bit segment command to a generalized version
pub fn from_64_lossy(
bytes: &'a [u8],
segment: &SegmentCommand64,
offset: usize,
ctx: container::Ctx,
) -> Result<Self, error::Error> {
Self::from_64_impl(bytes, segment, offset, ctx, true)
}
pub(crate) fn from_64_impl(
bytes: &'a [u8],
segment: &SegmentCommand64,
offset: usize,
ctx: container::Ctx,
lossy: bool,
) -> Result<Self, error::Error> { ) -> Result<Self, error::Error> {
Ok(Segment { Ok(Segment {
cmd: segment.cmd, cmd: segment.cmd,
@ -553,11 +508,7 @@ impl<'a> Segment<'a> {
initprot: segment.initprot, initprot: segment.initprot,
nsects: segment.nsects, nsects: segment.nsects,
flags: segment.flags, flags: segment.flags,
data: match segment_data(bytes, segment.fileoff, segment.filesize) { data: segment_data(bytes, segment.fileoff, segment.filesize)?,
Ok(v) => v,
Err(_) if lossy => &[],
Err(e) => return Err(e),
},
offset, offset,
raw_data: bytes, raw_data: bytes,
ctx, ctx,

Просмотреть файл

@ -17,7 +17,8 @@ use super::{section_table::SectionTable, PE};
static PADDING: [u8; 7] = [0; 7]; static PADDING: [u8; 7] = [0; 7];
impl PE<'_> { impl PE<'_> {
/// Returns the various ranges of the binary that are relevant for signature. /// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for
/// signature.
pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> { pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> {
ExcludedSectionsIter { ExcludedSectionsIter {
pe: self, pe: self,

Просмотреть файл

@ -1,6 +1,3 @@
//! Constants for flags that indicate attributes of the object or image file. These flags are used in the
//! [`goblin::pe::header::CoffHeader::characteristics`](crate::pe::header::CoffHeader::characteristics) field.
/* /*
type characteristic = type characteristic =
| IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_RELOCS_STRIPPED
@ -76,65 +73,27 @@ let show_type characteristics =
else "MANY" (* print all *) else "MANY" (* print all *)
*/ */
/// Image only, Windows CE, and Microsoft Windows NT and later. This indicates that the file does not
/// contain base relocations and must therefore be loaded at its preferred base address. If the base address
/// is not available, the loader reports an error. The default behavior of the linker is to strip base relocations
/// from executable (EXE) files.
pub const IMAGE_FILE_RELOCS_STRIPPED: u16 = 0x0001; pub const IMAGE_FILE_RELOCS_STRIPPED: u16 = 0x0001;
/// Image only. This indicates that the image file is valid and can be run.
/// If this flag is not set, it indicates a linker error.
pub const IMAGE_FILE_EXECUTABLE_IMAGE: u16 = 0x0002; pub const IMAGE_FILE_EXECUTABLE_IMAGE: u16 = 0x0002;
/// COFF line numbers have been removed. This flag is deprecated and should be zero.
pub const IMAGE_FILE_LINE_NUMS_STRIPPED: u16 = 0x0004; pub const IMAGE_FILE_LINE_NUMS_STRIPPED: u16 = 0x0004;
/// COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero.
pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: u16 = 0x0008; pub const IMAGE_FILE_LOCAL_SYMS_STRIPPED: u16 = 0x0008;
/// Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero.
pub const IMAGE_FILE_AGGRESSIVE_WS_TRIM: u16 = 0x0010; pub const IMAGE_FILE_AGGRESSIVE_WS_TRIM: u16 = 0x0010;
/// Application can handle > 2-GB addresses.
pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: u16 = 0x0020; pub const IMAGE_FILE_LARGE_ADDRESS_AWARE: u16 = 0x0020;
/// This flag is reserved for future use.
pub const RESERVED: u16 = 0x0040; pub const RESERVED: u16 = 0x0040;
/// Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory.
/// This flag is deprecated and should be zero.
pub const IMAGE_FILE_BYTES_REVERSED_LO: u16 = 0x0080; pub const IMAGE_FILE_BYTES_REVERSED_LO: u16 = 0x0080;
/// Machine is based on a 32-bit-word architecture.
pub const IMAGE_FILE_32BIT_MACHINE: u16 = 0x0100; pub const IMAGE_FILE_32BIT_MACHINE: u16 = 0x0100;
/// Debugging information is removed from the image file.
pub const IMAGE_FILE_DEBUG_STRIPPED: u16 = 0x0200; pub const IMAGE_FILE_DEBUG_STRIPPED: u16 = 0x0200;
/// If the image is on removable media, fully load it and copy it to the swap file.
pub const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP: u16 = 0x0400; pub const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP: u16 = 0x0400;
/// If the image is on network media, fully load it and copy it to the swap file.
pub const IMAGE_FILE_NET_RUN_FROM_SWAP: u16 = 0x0800; pub const IMAGE_FILE_NET_RUN_FROM_SWAP: u16 = 0x0800;
/// The image file is a system file, not a user program.
pub const IMAGE_FILE_SYSTEM: u16 = 0x1000; pub const IMAGE_FILE_SYSTEM: u16 = 0x1000;
/// The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run.
pub const IMAGE_FILE_DLL: u16 = 0x2000; pub const IMAGE_FILE_DLL: u16 = 0x2000;
/// The file should be run only on a uniprocessor machine.
pub const IMAGE_FILE_UP_SYSTEM_ONLY: u16 = 0x4000; pub const IMAGE_FILE_UP_SYSTEM_ONLY: u16 = 0x4000;
/// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
pub const IMAGE_FILE_BYTES_REVERSED_HI: u16 = 0x8000; pub const IMAGE_FILE_BYTES_REVERSED_HI: u16 = 0x8000;
/// Checks whether the characteristics value indicates that the file is a DLL (dynamically-linked library).
pub fn is_dll(characteristics: u16) -> bool { pub fn is_dll(characteristics: u16) -> bool {
characteristics & IMAGE_FILE_DLL == IMAGE_FILE_DLL characteristics & IMAGE_FILE_DLL == IMAGE_FILE_DLL
} }
/// Checks whether the characteristics value indicates that the file is an executable.
pub fn is_exe(characteristics: u16) -> bool { pub fn is_exe(characteristics: u16) -> bool {
characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == IMAGE_FILE_EXECUTABLE_IMAGE characteristics & IMAGE_FILE_EXECUTABLE_IMAGE == IMAGE_FILE_EXECUTABLE_IMAGE
} }

2
third_party/rust/goblin/src/pe/debug.rs поставляемый
Просмотреть файл

@ -92,7 +92,7 @@ impl ImageDebugDirectory {
) )
} }
pub(crate) fn parse_with_opts( fn parse_with_opts(
bytes: &[u8], bytes: &[u8],
dd: data_directories::DataDirectory, dd: data_directories::DataDirectory,
sections: &[section_table::SectionTable], sections: &[section_table::SectionTable],

Просмотреть файл

@ -1,38 +0,0 @@
//! Constants for characteristics of image files. These constants are used in the
//! [`goblin::pe::optional_header::WindowsFields::dll_characteristics`](crate::pe::optional_header::WindowsFields::dll_characteristics)
//! field.
//!
//! The values 0x0001, 0x0002, 0x0004, 0x0008 are reserved for future use and must be zero.
/// Image can handle a high entropy 64-bit virtual address space.
pub const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA: u16 = 0x0020;
/// DLL can be relocated at load time.
pub const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE: u16 = 0x0040;
/// Code Integrity checks are enforced.
pub const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY: u16 = 0x0080;
/// Image is NX compatible.
pub const IMAGE_DLLCHARACTERISTICS_NX_COMPAT: u16 = 0x0100;
/// Isolation aware, but do not isolate the image.
pub const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION: u16 = 0x0200;
/// Does not use structured exception (SE) handling. No SE handler may be called in this image.
pub const IMAGE_DLLCHARACTERISTICS_NO_SEH: u16 = 0x0400;
/// Do not bind the image.
pub const IMAGE_DLLCHARACTERISTICS_NO_BIND: u16 = 0x0800;
/// Image must execute in an AppContainer.
pub const IMAGE_DLLCHARACTERISTICS_APPCONTAINER: u16 = 0x1000;
/// A WDM driver.
pub const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER: u16 = 0x2000;
/// Image supports Control Flow Guard.
pub const IMAGE_DLLCHARACTERISTICS_GUARD_CF: u16 = 0x4000;
/// Terminal Server aware.
pub const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE: u16 = 0x8000;

2
third_party/rust/goblin/src/pe/exception.rs поставляемый
Просмотреть файл

@ -612,7 +612,7 @@ impl<'a> UnwindInfo<'a> {
/// Returns an iterator over unwind codes in this unwind info. /// Returns an iterator over unwind codes in this unwind info.
/// ///
/// Unwind codes are iterated in descending `code_offset` order suitable for unwinding. If the /// Unwind codes are iterated in descending `code_offset` order suitable for unwinding. If the
/// optional [`chained_info`](Self::chained_info) is present, codes of that unwind info should be interpreted /// optional [`chained_info`] is present, codes of that unwind info should be interpreted
/// immediately afterwards. /// immediately afterwards.
pub fn unwind_codes(&self) -> UnwindCodeIterator<'a> { pub fn unwind_codes(&self) -> UnwindCodeIterator<'a> {
UnwindCodeIterator { UnwindCodeIterator {

741
third_party/rust/goblin/src/pe/header.rs поставляемый
Просмотреть файл

@ -1,296 +1,54 @@
use crate::error; use crate::error;
use crate::pe::{data_directories, optional_header, section_table, symbol}; use crate::pe::{optional_header, section_table, symbol};
use crate::strtab; use crate::strtab;
use alloc::vec::Vec; use alloc::vec::Vec;
use log::debug; use log::debug;
use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith}; use scroll::{ctx, IOread, IOwrite, Pread, Pwrite, SizeWith};
/// In `winnt.h` and `pe.h`, it's `IMAGE_DOS_HEADER`. It's a DOS header present in all PE binaries. /// DOS header present in all PE binaries
///
/// The DOS header is a relic from the MS-DOS era. It used to be useful to display an
/// error message if the binary is run in MS-DOS by utilizing the DOS stub.
///
/// Nowadays, only two fields from
/// the DOS header are used on Windows: [`signature` (aka `e_magic`)](DosHeader::signature)
/// and [`pe_pointer` (aka `e_lfanew`)](DosHeader::pe_pointer).
///
/// ## Position in a modern PE file
///
/// The DOS header is located at the beginning of the PE file and is usually followed by the [DosStub].
///
/// ## Note on the archaic "formatted header"
///
/// The subset of the structure spanning from its start to the [`overlay_number` (aka `e_ovno`)](DosHeader::overlay_number) field
/// included (i.e. till the offset 0x1C) used to be commonly known as "formatted header", since their position and contents were
/// fixed. Optional information used by overlay managers could have followed the formatted header. In the absence of optional
/// information, the formatted header was followed by the ["relocation pointer table"](https://www.tavi.co.uk/phobos/exeformat.html#reloctable).
///
/// Overlays were sections of a program that remained on disk until the program actually required them. Different overlays
/// could thus share the same memory area. The overlays were loaded and unloaded by special code provided by the program
/// or its run-time library.
///
/// [Source](https://www.tavi.co.uk/phobos/exeformat.html#:~:text=Format%20of%20the%20.EXE%20file%20header).
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pwrite)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pwrite)]
#[doc(alias("IMAGE_DOS_HEADER"))]
pub struct DosHeader { pub struct DosHeader {
/// Magic number: `[0x5A, 0x4D]`. In [little endian](https://en.wikipedia.org/wiki/Endianness) /// Magic number: 5a4d
/// [ASCII](https://en.wikipedia.org/wiki/ASCII), it reads "MZ" for [Mark Zbikowski](https://en.wikipedia.org/wiki/Mark_Zbikowski)).
///
/// ## Non-MZ DOS executables
///
/// * For [IBM OS/2](https://www.britannica.com/technology/IBM-OS-2), the value was "NE".
/// * For IBM OS/2 LE, the value was "LE".
/// * For [NT](https://en.wikipedia.org/wiki/Windows_NT), the value was "PE00".
///
/// Sources:
///
/// * <https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/>
/// * <https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail>
#[doc(alias("e_magic"))]
pub signature: u16, pub signature: u16,
/// In `winnt.h` and `pe.h`, it's `e_cblp`. /// e_cblp
///
/// It used to specify the number of bytes actually used in the last "page".
/// Page used to refer to a segment of memory, usually of 512 bytes size.
///
/// The case of full page was represented by 0x0000 (since the last page is never empty).
///
/// For example, assuming a page size of 512 bytes, this value would
/// be 0x0000 for a 1024 byte file, and 0x0001 for a 1025 byte file
/// (since it only contains one valid byte).
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_cblp"))]
pub bytes_on_last_page: u16, pub bytes_on_last_page: u16,
/// In `winnt.h` and `pe.h`, it's `e_cp`. /// e_cp
///
/// It used to specify the number of pages required to hold a file. For example,
/// if the file contained 1024 bytes, and the file had pages of a size of 512 bytes,
/// this [word](https://en.wikipedia.org/wiki/Word_(computer_architecture)) would contain
/// 0x0002 (2 pages); if the file contained 1025 bytes, this word would contain 0x0003 (3 pages).
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_cp"))]
pub pages_in_file: u16, pub pages_in_file: u16,
/// In `winnt.h` and `pe.h`, it's `e_crlc`. /// e_crlc
///
/// It used to specify the number of "relocation items", i.e. the number of entries that
/// existed in the ["relocation pointer table"](https://www.tavi.co.uk/phobos/exeformat.html#reloctable).
/// If there were no relocations, this field would contain 0x0000.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// ## On relocation items and relocation pointer table
///
/// When a program is compiled, memory addresses are often hard-coded into the binary code.
/// These addresses are usually relative to the base address where the program expects to be loaded into memory.
/// However, when the program is loaded into memory, it might not be loaded at its preferred base address due to
/// various reasons such as memory fragmentation or other programs already occupying that space.
///
/// Relocation items, also known as fixups or relocations, are pieces of data embedded within the executable file
/// that indicate which memory addresses need to be adjusted when the program is loaded at a different base address.
/// These relocations specify the location and type of adjustment needed.
///
/// The relocation pointer table is a data structure that contains pointers to the locations within the executable file
/// where relocations need to be applied. It allows the operating system's loader to efficiently locate and process the
/// relocation data during the loading process.
///
/// ---
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_crlc"))]
pub relocations: u16, pub relocations: u16,
/// In `winnt.h` and `pe.h`, it's `e_cparhdr`. /// e_cparhdr
///
/// It used to specify the size of the "executable header" in terms of "paragraphs" (16 byte chunks). It used to indicate
/// the offset of the program's compiled/assembled and linked image (the [load module](https://www.tavi.co.uk/phobos/exeformat.html#loadmodule)) within the executable file. The size
/// of the load module could have been deduced by substructing this value (converted to bytes) from the overall size that could
/// have been derived from combining the value of [`pages_in_file` (aka `e_cp`)](DosHeader::pages_in_file) and the value of
/// [`bytes_on_last_page` (aka `e_cblp)`](DosHeader::bytes_on_last_page). The header used to always span an even number of
/// paragraphs.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// The "executable header" in this context refers to the DOS header itself.
///
/// Typically, this field is set to 4. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
/// This is because the modern DOS header is 64 bytes long, and 64 / 16 = 4.
#[doc(alias("e_cparhdr"))]
pub size_of_header_in_paragraphs: u16, pub size_of_header_in_paragraphs: u16,
/// In `winnt.h` and `pe.h`, it's `e_minalloc`. /// e_minalloc
///
/// It used to specify the minimum number of extra paragraphs needed to be allocated to begin execution. This is
/// **in addition** to the memory required to hold the [load module](https://www.tavi.co.uk/phobos/exeformat.html#loadmodule). This value normally represented the total size
/// of any uninitialized data and/or stack segments that were linked at the end of the program. This space was not
/// directly included in the load module, since there were no particular initializing values and it would simply waste
/// disk space.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// If both the [`minimum_extra_paragraphs_needed` (aka `e_minalloc`)](DosHeader::minimum_extra_paragraphs_needed) and
/// [`maximum_extra_paragraphs_needed` (aka `e_maxalloc`)](DosHeader::maximum_extra_paragraphs_needed) fields were set to 0x0000,
/// the program would be allocated as much memory as available. [Source](https://www.tavi.co.uk/phobos/exeformat.html)
///
/// Typically, this field is set to 0x10. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_minalloc"))]
pub minimum_extra_paragraphs_needed: u16, pub minimum_extra_paragraphs_needed: u16,
/// In `winnt.h` and `pe.h`, it's `e_maxalloc`. /// e_maxalloc
///
/// It used to specify the maximum number of extra paragraphs needed to be allocated by to begin execution. This indicated
/// **additional** memory over and above that required by the [load module](https://www.tavi.co.uk/phobos/exeformat.html#loadmodule) and the value specified in
/// [`minimum_extra_paragraphs_needed` (aka `e_minalloc`)](DosHeader::minimum_extra_paragraphs_needed).
/// If the request could not be satisfied, the program would be allocated as much memory as available.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// If both the [`minimum_extra_paragraphs_needed` (aka `e_minalloc`)](DosHeader::minimum_extra_paragraphs_needed) and
/// [`maximum_extra_paragraphs_needed` (aka `e_maxalloc`)](DosHeader::maximum_extra_paragraphs_needed) fields were set to 0x0000,
/// the program would be allocated as much memory as available. [Source](https://www.tavi.co.uk/phobos/exeformat.html)
///
/// Typically, this field is set to 0xFFFF. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_maxalloc"))]
pub maximum_extra_paragraphs_needed: u16, pub maximum_extra_paragraphs_needed: u16,
/// In `winnt.h` and `pe.h`, it's `e_ss`. /// e_ss
///
/// It used to specify the initial SS ("stack segment") value. SS value was a paragraph address of the stack segment
/// relative to the start of the [load module](https://www.tavi.co.uk/phobos/exeformat.html#loadmodule). At load time, the value was relocated by adding the address of the
/// start segment of the program to it, and the resulting value was placed in the SS register before the program is
/// started. To read more about x86 memory segmentation and SS register, see the
/// [wikipedia article](https://en.wikipedia.org/wiki/X86_memory_segmentation) on this topic. In DOS, the start segment
/// boundary of the program was the first segment boundary in memory after
/// [Program Segment Prefix (PSP)](https://en.wikipedia.org/wiki/Program_Segment_Prefix).
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// The Program Segment Prefix (PSP) was a data structure used in DOS (Disk Operating System) environments.
/// It was located at the beginning of the memory allocated for a running program and it contained various
/// pieces of information about the program, including command-line arguments, environment variables,
/// and pointers to various system resources.
///
/// [According to Wikipedia](https://en.wikipedia.org/wiki/Data_segment#Stack), the stack segment contains the call stack,
/// a LIFO structure, typically located in the higher parts of memory. A "stack pointer" register tracks the top of the
/// stack; it is adjusted each time a value is "pushed" onto the stack. The set of values pushed for one function call
/// is termed a "stack frame".
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_ss"))]
pub initial_relative_ss: u16, pub initial_relative_ss: u16,
/// In `winnt.h` and `pe.h`, it's `e_sp`. /// e_sp
///
/// It used to specify the initial SP ("stack pointer") value. SP value was the absolute value that must have been loaded
/// into the SP register before the program is given control. Since the actual stack segment was determined by the loader,
/// and this was merely a value within that segment, it didn't need to be relocated.
///
/// [According to Wikipedia](https://en.wikipedia.org/wiki/Data_segment#Stack), the stack segment contains the call stack,
/// a LIFO structure, typically located in the higher parts of memory. A "stack pointer" register tracks the top of the
/// stack; it is adjusted each time a value is "pushed" onto the stack. The set of values pushed for one function call
/// is termed a "stack frame".
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0xB8. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
// TODO: Clarify what exactly is meany by "this was merely a value within that segment".
#[doc(alias("e_sp"))]
pub initial_sp: u16, pub initial_sp: u16,
/// In `winnt.h` and `pe.h`, it's `e_csum`. /// e_csum
///
/// It used to specify the checksum of the contents of the executable file It used to ensure the integrity of the data
/// within the file. For full details on how this checksum was calculated, see <http://www.tavi.co.uk/phobos/exeformat.html#checksum>.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_csum"))]
pub checksum: u16, pub checksum: u16,
/// In `winnt.h` and `pe.h`, it's `e_ip`. /// e_ip
///
/// It used to specify the initial IP ("instruction pointer") value. IP value was the absolute value that must have been
/// loaded into the IP register in order to transfer control to the program. Since the actual code segment was determined
/// by the loader and, and this was merely a value within that segment, it didn't need to be relocated.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
// TODO: Clarify what exactly is meany by "this was merely a value within that segment".
#[doc(alias("e_ip"))]
pub initial_ip: u16, pub initial_ip: u16,
/// In `winnt.h` and `pe.h`, it's `e_cs`. /// e_cs
///
/// It used to specify the pre-relocated initial CS ("code segment") value relative to the start of the [load module](https://www.tavi.co.uk/phobos/exeformat.html#loadmodule),
/// that should have been placed in the CS register in order to transfer control to the program. At load time, this value
/// was relocated by adding the address of the start segment of the program to it, and the resulting value was placed in
/// the CS register when control is transferred.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_cs"))]
pub initial_relative_cs: u16, pub initial_relative_cs: u16,
/// In `winnt.h` and `pe.h`, it's `e_lfarlc`. /// e_lfarlc
///
/// It used to specify the logical file address of the relocation table, or more specifically, the offset from the start
/// of the file to the [relocation pointer table](https://www.tavi.co.uk/phobos/exeformat.html#reloctable). This value
/// must have been used to locate the relocation table (rather than assuming a fixed location) because variable-length
/// information pertaining to program overlays could have occurred before this table, causing its position to vary.
/// A value of 0x40 in this field generally indicated a different kind of executable, not a DOS 'MZ' type.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0x40. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_lfarlc"))]
pub file_address_of_relocation_table: u16, pub file_address_of_relocation_table: u16,
/// In `winnt.h` and `pe.h`, it's `e_ovno`. /// e_ovno
///
/// It used to specify the overlay number, which was normally set to 0x0000, because few programs actually had overlays.
/// It changed only in files containing programs that used overlays.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Overlays were sections of a program that remained on disk until the program actually required them. Different overlays
/// could thus share the same memory area. The overlays were loaded and unloaded by special code provided by the program
/// or its run-time library.
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_ovno"))]
pub overlay_number: u16, pub overlay_number: u16,
/// In `winnt.h` and `pe.h`, it's `e_res[4]`. /// e_res[4]
///
/// It used to specify the reserved words for the program, i.e. an array reserved for future use.
/// Usually, the array was zeroed by the linker.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_res"))]
pub reserved: [u16; 4], pub reserved: [u16; 4],
/// In `winnt.h` and `pe.h`, it's `e_oemid`. /// e_oemid
///
/// It used to specify the identifier for the OEM ("Original Equipment Manufacturer") for [`oem_info` aka `e_oeminfo`](DosHeader::oem_info).
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// More specifically, it used to specify the OEM of the system or hardware platform for which the executable file was created.
/// This field was used to specify certain characteristics or requirements related to the hardware environment in which the
/// executable was intended to run.
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_oemid"))]
pub oem_id: u16, pub oem_id: u16,
/// In `winnt.h` and `pe.h`, it's `e_oeminfo`. /// e_oeminfo
///
/// It used to specify the extra information, the kind of which was specific to the OEM identified by [`oem_id` aka `e_oemid`](DosHeader::oem_id).
#[doc(alias("e_oeminfo"))]
pub oem_info: u16, pub oem_info: u16,
/// In `winnt.h` and `pe.h`, it's `e_res2[10]`. /// e_res2[10]
///
/// It used to specify the reserved words for the program, i.e. an array reserved for future use.
/// Usually, the array was zeroed by the linker.
/// [Source](https://stixproject.github.io/data-model/1.2/WinExecutableFileObj/DOSHeaderType/).
///
/// Typically, this field is set to 0. [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/dos-header/).
#[doc(alias("e_res2"))]
pub reserved2: [u16; 10], pub reserved2: [u16; 10],
/// In `winnt.h` and `pe.h`, it's `e_lfanew`. /// e_lfanew: pointer to PE header, always at offset 0x3c
///
/// Today, it specifies the logcal file address of the of the new exe header. In particular, it is a 4-byte offset into
/// the file where the PE file header is located. It is necessary to use this offset to locate the PE header in the file.
///
/// Typically, this field is set to 0x3c ([`PE_POINTER_OFFSET`]).
#[doc(alias("e_lfanew"))]
pub pe_pointer: u32, pub pe_pointer: u32,
} }
#[doc(alias("IMAGE_DOS_SIGNATURE"))]
pub const DOS_MAGIC: u16 = 0x5a4d; pub const DOS_MAGIC: u16 = 0x5a4d;
pub const PE_POINTER_OFFSET: u32 = 0x3c; pub const PE_POINTER_OFFSET: u32 = 0x3c;
pub const DOS_STUB_OFFSET: u32 = PE_POINTER_OFFSET + (core::mem::size_of::<u32>() as u32); pub const DOS_STUB_OFFSET: u32 = PE_POINTER_OFFSET + (core::mem::size_of::<u32>() as u32);
@ -321,10 +79,12 @@ impl DosHeader {
let initial_relative_cs = bytes.gread_with(&mut offset, scroll::LE)?; let initial_relative_cs = bytes.gread_with(&mut offset, scroll::LE)?;
let file_address_of_relocation_table = bytes.gread_with(&mut offset, scroll::LE)?; let file_address_of_relocation_table = bytes.gread_with(&mut offset, scroll::LE)?;
let overlay_number = bytes.gread_with(&mut offset, scroll::LE)?; let overlay_number = bytes.gread_with(&mut offset, scroll::LE)?;
let reserved = bytes.gread_with(&mut offset, scroll::LE)?; // 4 let reserved = [0x0; 4];
offset += core::mem::size_of_val(&reserved);
let oem_id = bytes.gread_with(&mut offset, scroll::LE)?; let oem_id = bytes.gread_with(&mut offset, scroll::LE)?;
let oem_info = bytes.gread_with(&mut offset, scroll::LE)?; let oem_info = bytes.gread_with(&mut offset, scroll::LE)?;
let reserved2 = bytes.gread_with(&mut offset, scroll::LE)?; // 10 let reserved2 = [0x0; 10];
offset += core::mem::size_of_val(&reserved2);
debug_assert!( debug_assert!(
offset == PE_POINTER_OFFSET as usize, offset == PE_POINTER_OFFSET as usize,
@ -383,14 +143,7 @@ impl DosHeader {
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Pread, Pwrite)] #[derive(Debug, PartialEq, Copy, Clone, Pread, Pwrite)]
/// The DOS stub program which should be executed in DOS mode. It prints the message "This program cannot be run in DOS mode" and exits. /// The DOS stub program which should be executed in DOS mode
///
/// ## Position in a modern PE file
///
/// The [DosStub] is usually located immediately after the [DosHeader] and...
///
/// * De facto, can be followed by a non-standard ["Rich header"](https://0xrick.github.io/win-internals/pe3/#rich-header).
/// * According to the standard, is followed by the [Header::signature] and then the [CoffHeader].
pub struct DosStub(pub [u8; 0x40]); pub struct DosStub(pub [u8; 0x40]);
impl Default for DosStub { impl Default for DosStub {
fn default() -> Self { fn default() -> Self {
@ -405,99 +158,17 @@ impl Default for DosStub {
} }
} }
/// In `winnt.h`, it's `IMAGE_FILE_HEADER`. COFF Header. /// COFF Header
///
/// Together with the [Header::signature] and the [Header::optional_header], it forms the
/// [`IMAGE_NT_HEADERS`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_nt_headers32).
///
/// ## Position in a modern PE file
///
/// The COFF header is located after the [Header::signature], which in turn is located after the
/// non-standard ["Rich header"](https://0xrick.github.io/win-internals/pe3/#rich-header), if present,
/// and after the [DosStub], according to the standard.
///
/// COFF header is followed by the [Header::optional_header].
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
#[doc(alias("IMAGE_FILE_HEADER"))]
pub struct CoffHeader { pub struct CoffHeader {
/// The architecture type of the computer. An image file can only be run /// The machine type
/// on the specified computer or a system that emulates the specified computer.
///
/// Can be one of the following values:
///
/// * [`COFF_MACHINE_UNKNOWN`],
/// * [`COFF_MACHINE_ALPHA`],
/// * [`COFF_MACHINE_ALPHA64`],
/// * [`COFF_MACHINE_AM33`],
/// * [`COFF_MACHINE_X86_64`],
/// * [`COFF_MACHINE_ARM`],
/// * [`COFF_MACHINE_ARM64`],
/// * [`COFF_MACHINE_ARMNT`],
/// * [`COFF_MACHINE_EBC`],
/// * [`COFF_MACHINE_X86`],
/// * [`COFF_MACHINE_IA64`],
/// * [`COFF_MACHINE_LOONGARCH32`],
/// * [`COFF_MACHINE_LOONGARCH64`],
/// * [`COFF_MACHINE_M32R`],
/// * [`COFF_MACHINE_MIPS16`],
/// * [`COFF_MACHINE_MIPSFPU`],
/// * [`COFF_MACHINE_MIPSFPU16`],
/// * [`COFF_MACHINE_POWERPC`],
/// * [`COFF_MACHINE_POWERPCFP`],
/// * [`COFF_MACHINE_R4000`],
/// * [`COFF_MACHINE_RISCV32`],
/// * [`COFF_MACHINE_RISCV64`],
/// * [`COFF_MACHINE_RISCV128`],
/// * [`COFF_MACHINE_SH3`],
/// * [`COFF_MACHINE_SH3DSP`],
/// * [`COFF_MACHINE_SH4`],
/// * [`COFF_MACHINE_SH5`],
/// * [`COFF_MACHINE_THUMB`],
/// * [`COFF_MACHINE_WCEMIPSV2`],
///
/// or any other value that is not listed here.
///
/// The constants above are sourced from <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types>.
/// If there's a missing constant, please open an issue or a pull request.
// TODO: insert the values names with a macro
#[doc(alias("Machine"))]
pub machine: u16, pub machine: u16,
/// The number of sections. This indicates the size of the section table, which immediately follows the headers.
/// Note that the Windows loader limits the number of sections to 96.
/// [Source](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_file_header).
#[doc(alias("NumberOfSections"))]
pub number_of_sections: u16, pub number_of_sections: u16,
/// The low 32 bits of the time stamp of the image. This represents the date and time the image was created by the linker.
/// The value is represented in the number of seconds elapsed since midnight (00:00:00), January 1, 1970, Universal
/// Coordinated Time, according to the system clock.
#[doc(alias("TimeDateStamp"))]
pub time_date_stamp: u32, pub time_date_stamp: u32,
/// The offset of the symbol table, in bytes, or zero if no COFF symbol table exists.
///
/// Typically, this field is set to 0 because COFF debugging information is deprecated.
/// [Source](https://0xrick.github.io/win-internals/pe4/#file-header-image_file_header).
// TODO: further explain the COFF symbol table. This seems to be a nuanced topic.
#[doc(alias("PointerToSymbolTable"))]
pub pointer_to_symbol_table: u32, pub pointer_to_symbol_table: u32,
/// The number of symbols in the symbol table.
///
/// Typically, this field is set to 0 because COFF debugging information is deprecated.
/// [Source](https://0xrick.github.io/win-internals/pe4/#file-header-image_file_header).
// Q (JohnScience): Why is the name `number_of_symbol_table` and not `number_of_symbols`?
#[doc(alias("NumberOfSymbols"))]
pub number_of_symbol_table: u32, pub number_of_symbol_table: u32,
/// The size of the optional header, in bytes. This value should be zero for object files.
///
/// The [`goblin::pe::optional_header::OptionalHeader`](crate::pe::optional_header::OptionalHeader) is meant to
/// represent either the 32-bit or the 64-bit optional header. The size of the optional header is used to determine
/// which one it is.
#[doc(alias("SizeOfOptionalHeader"))]
pub size_of_optional_header: u16, pub size_of_optional_header: u16,
/// The [characteristics](https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics) of the image.
///
/// The constants for the characteristics are available in the [`goblin::pe::characteristic`](crate::pe::characteristic) module.
#[doc(alias("Characteristics"))]
pub characteristics: u16, pub characteristics: u16,
} }
@ -505,200 +176,55 @@ pub const SIZEOF_COFF_HEADER: usize = 20;
/// PE\0\0, little endian /// PE\0\0, little endian
pub const PE_MAGIC: u32 = 0x0000_4550; pub const PE_MAGIC: u32 = 0x0000_4550;
pub const SIZEOF_PE_MAGIC: usize = 4; pub const SIZEOF_PE_MAGIC: usize = 4;
/// The contents of this field are assumed to be applicable to any machine type
// Q (JohnScience): doesn't it make sense to move all these constants to a dedicated module
// and then re-export them from here? This way, the module will be more organized.
//
// Also, don't we want to declare them in a macro to remove the boilerplate and make the implementation
// of `machine_to_str` more future-proof and concise? For example, addition of...
//
// * `IMAGE_FILE_MACHINE_LOONGARCH32`,
// * `IMAGE_FILE_MACHINE_LOONGARCH64`,
// * `IMAGE_FILE_MACHINE_ALPHA`,
// * `IMAGE_FILE_MACHINE_ALPHA64`
//
// didn't trigger the exhaustiveness check because there was a necessary default case.
//
// This way, we can also generate a test that would parse <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types>
// and check that there are no missing constants.
/// The contents of this field are assumed to be applicable to any machine type.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_UNKNOWN"))]
pub const COFF_MACHINE_UNKNOWN: u16 = 0x0; pub const COFF_MACHINE_UNKNOWN: u16 = 0x0;
/// Matsushita AM33
/// Alpha AXP, 32-bit address space.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_ALPHA"))]
pub const COFF_MACHINE_ALPHA: u16 = 0x184;
/// Alpha AXP, 64-bit address space.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_ALPHA64"))]
#[doc(alias("IMAGE_FILE_MACHINE_AXP64"))]
pub const COFF_MACHINE_ALPHA64: u16 = 0x284;
/// Matsushita AM33.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_AM33"))]
pub const COFF_MACHINE_AM33: u16 = 0x1d3; pub const COFF_MACHINE_AM33: u16 = 0x1d3;
/// x64
/// x64 aka amd64.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_AMD64"))]
// Q (JohnScience): why is this `COFF_MACHINE_X86_64` and not `COFF_MACHINE_AMD64`?
// Should we deprecate the former and use the latter instead?
pub const COFF_MACHINE_X86_64: u16 = 0x8664; pub const COFF_MACHINE_X86_64: u16 = 0x8664;
/// ARM little endian
/// ARM little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_ARM"))]
pub const COFF_MACHINE_ARM: u16 = 0x1c0; pub const COFF_MACHINE_ARM: u16 = 0x1c0;
/// ARM64 little endian
/// ARM64 little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_ARM64"))]
pub const COFF_MACHINE_ARM64: u16 = 0xaa64; pub const COFF_MACHINE_ARM64: u16 = 0xaa64;
/// ARM Thumb-2 little endian
/// ARM Thumb-2 little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_ARMNT"))]
pub const COFF_MACHINE_ARMNT: u16 = 0x1c4; pub const COFF_MACHINE_ARMNT: u16 = 0x1c4;
/// EFI byte code
/// EFI byte code.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_EBC"))]
pub const COFF_MACHINE_EBC: u16 = 0xebc; pub const COFF_MACHINE_EBC: u16 = 0xebc;
/// Intel 386 or later processors and compatible processors
/// Intel 386 or later processors and compatible processors.
///
/// One of the possible values for [`CoffHeader::machine`].
// Q (JohnScience): why is this `COFF_MACHINE_X86` and not `COFF_MACHINE_I386`?
// Should we deprecate the former and use the latter instead?
#[doc(alias("IMAGE_FILE_MACHINE_I386"))]
pub const COFF_MACHINE_X86: u16 = 0x14c; pub const COFF_MACHINE_X86: u16 = 0x14c;
/// Intel Itanium processor family
/// Intel Itanium processor family.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_IA64"))]
pub const COFF_MACHINE_IA64: u16 = 0x200; pub const COFF_MACHINE_IA64: u16 = 0x200;
/// Mitsubishi M32R little endian
/// LoongArch 32-bit processor family.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH32"))]
pub const COFF_MACHINE_LOONGARCH32: u16 = 0x6232;
/// LoongArch 64-bit processor family.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_LOONGARCH64"))]
pub const COFF_MACHINE_LOONGARCH64: u16 = 0x6264;
/// Mitsubishi M32R little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_M32R"))]
pub const COFF_MACHINE_M32R: u16 = 0x9041; pub const COFF_MACHINE_M32R: u16 = 0x9041;
/// MIPS16
/// MIPS16.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_MIPS16"))]
pub const COFF_MACHINE_MIPS16: u16 = 0x266; pub const COFF_MACHINE_MIPS16: u16 = 0x266;
/// MIPS with FPU
/// MIPS with FPU.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU"))]
pub const COFF_MACHINE_MIPSFPU: u16 = 0x366; pub const COFF_MACHINE_MIPSFPU: u16 = 0x366;
/// MIPS16 with FPU
/// MIPS16 with FPU.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_MIPSFPU16"))]
pub const COFF_MACHINE_MIPSFPU16: u16 = 0x466; pub const COFF_MACHINE_MIPSFPU16: u16 = 0x466;
/// Power PC little endian
/// Power PC little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_POWERPC"))]
pub const COFF_MACHINE_POWERPC: u16 = 0x1f0; pub const COFF_MACHINE_POWERPC: u16 = 0x1f0;
/// Power PC with floating point support
/// Power PC with floating point support.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_POWERPCFP"))]
pub const COFF_MACHINE_POWERPCFP: u16 = 0x1f1; pub const COFF_MACHINE_POWERPCFP: u16 = 0x1f1;
/// MIPS little endian
/// MIPS little endian.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_R4000"))]
pub const COFF_MACHINE_R4000: u16 = 0x166; pub const COFF_MACHINE_R4000: u16 = 0x166;
/// RISC-V 32-bit address space
/// RISC-V 32-bit address space.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_RISCV32"))]
pub const COFF_MACHINE_RISCV32: u16 = 0x5032; pub const COFF_MACHINE_RISCV32: u16 = 0x5032;
/// RISC-V 64-bit address space
/// RISC-V 64-bit address space.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_RISCV64"))]
pub const COFF_MACHINE_RISCV64: u16 = 0x5064; pub const COFF_MACHINE_RISCV64: u16 = 0x5064;
/// RISC-V 128-bit address space /// RISC-V 128-bit address space
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_RISCV128"))]
pub const COFF_MACHINE_RISCV128: u16 = 0x5128; pub const COFF_MACHINE_RISCV128: u16 = 0x5128;
/// Hitachi SH3
/// Hitachi SH3.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_SH3"))]
pub const COFF_MACHINE_SH3: u16 = 0x1a2; pub const COFF_MACHINE_SH3: u16 = 0x1a2;
/// Hitachi SH3 DSP
/// Hitachi SH3 DSP.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_SH3DSP"))]
pub const COFF_MACHINE_SH3DSP: u16 = 0x1a3; pub const COFF_MACHINE_SH3DSP: u16 = 0x1a3;
/// Hitachi SH4
/// Hitachi SH4.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_SH4"))]
pub const COFF_MACHINE_SH4: u16 = 0x1a6; pub const COFF_MACHINE_SH4: u16 = 0x1a6;
/// Hitachi SH5
/// Hitachi SH5.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_SH5"))]
pub const COFF_MACHINE_SH5: u16 = 0x1a8; pub const COFF_MACHINE_SH5: u16 = 0x1a8;
/// Thumb
/// Thumb.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_THUMB"))]
pub const COFF_MACHINE_THUMB: u16 = 0x1c2; pub const COFF_MACHINE_THUMB: u16 = 0x1c2;
/// MIPS little-endian WCE v2
/// MIPS little-endian WCE v2.
///
/// One of the possible values for [`CoffHeader::machine`].
#[doc(alias("IMAGE_FILE_MACHINE_WCEMIPSV2"))]
pub const COFF_MACHINE_WCEMIPSV2: u16 = 0x169; pub const COFF_MACHINE_WCEMIPSV2: u16 = 0x169;
impl CoffHeader { impl CoffHeader {
@ -767,23 +293,11 @@ impl CoffHeader {
} }
} }
/// The PE header.
///
/// ## Position in a modern PE file
///
/// The PE header is located at the very beginning of the file and
/// is followed by the section table and sections.
#[derive(Debug, PartialEq, Copy, Clone, Default)] #[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct Header { pub struct Header {
pub dos_header: DosHeader, pub dos_header: DosHeader,
/// DOS program for legacy loaders /// DOS program for legacy loaders
pub dos_stub: DosStub, pub dos_stub: DosStub,
// Q (JohnScience): should we care about the "rich header"?
// https://0xrick.github.io/win-internals/pe3/#rich-header
// Introducing it would be a breaking change because it would require a new field in the struct
// but it would be a good addition to the library.
//
/// PE Magic: PE\0\0, little endian /// PE Magic: PE\0\0, little endian
pub signature: u32, pub signature: u32,
pub coff_header: CoffHeader, pub coff_header: CoffHeader,
@ -835,167 +349,18 @@ impl ctx::TryIntoCtx<scroll::Endian> for Header {
} }
} }
/// The TE header is a reduced PE32/PE32+ header containing only fields /// Convert machine to str representation
/// required for execution in the Platform Initialization
/// ([PI](https://uefi.org/specs/PI/1.8/V1_Introduction.html)) architecture.
/// The TE header is described in this specification:
/// <https://uefi.org/specs/PI/1.8/V1_TE_Image.html#te-header>
#[cfg(feature = "te")]
#[repr(C)]
#[derive(Debug, Default, PartialEq, Copy, Clone, Pread, Pwrite)]
pub struct TeHeader {
/// Te signature, always [TE_MAGIC]
pub signature: u16,
/// The machine type
pub machine: u16,
/// The number of sections
pub number_of_sections: u8,
/// The subsystem
pub subsystem: u8,
/// the amount of bytes stripped from the header when converting from a
/// PE32/PE32+ header to a TE header. Used to resolve addresses
pub stripped_size: u16,
/// The entry point of the binary
pub entry_point: u32,
/// The base of the code section
pub base_of_code: u32,
/// The image base
pub image_base: u64,
/// The size and address of the relocation directory
pub reloc_dir: data_directories::DataDirectory,
/// The size and address of the debug directory
pub debug_dir: data_directories::DataDirectory,
}
#[cfg(feature = "te")]
#[doc(alias("IMAGE_TE_SIGNATURE"))]
pub const TE_MAGIC: u16 = 0x5a56;
#[cfg(feature = "te")]
impl TeHeader {
/// Parse the TE header from the given bytes.
pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result<Self> {
let mut header: TeHeader = bytes.gread_with(offset, scroll::LE)?;
let adj_offset = header.stripped_size as u32 - core::mem::size_of::<TeHeader>() as u32;
header.fixup_header(adj_offset);
Ok(header)
}
/// Parse the sections from the TE header.
pub fn sections(
&self,
bytes: &[u8],
offset: &mut usize,
) -> error::Result<Vec<section_table::SectionTable>> {
let adj_offset = self.stripped_size as u32 - core::mem::size_of::<TeHeader>() as u32;
let nsections = self.number_of_sections as usize;
// a section table is at least 40 bytes
if nsections > bytes.len() / 40 {
return Err(error::Error::BufferTooShort(nsections, "sections"));
}
let mut sections = Vec::with_capacity(nsections);
for i in 0..nsections {
let mut section = section_table::SectionTable::parse(bytes, offset, 0)?;
TeHeader::fixup_section(&mut section, adj_offset);
debug!("({}) {:#?}", i, section);
sections.push(section);
}
Ok(sections)
}
// Adjust addresses in the header to account for the stripped size
fn fixup_header(&mut self, adj_offset: u32) {
debug!(
"Entry point fixed up from: 0x{:x} to 0x{:X}",
self.entry_point,
self.entry_point.wrapping_sub(adj_offset)
);
self.entry_point = self.entry_point.wrapping_sub(adj_offset);
debug!(
"Base of code fixed up from: 0x{:x} to 0x{:X}",
self.base_of_code,
self.base_of_code.wrapping_sub(adj_offset)
);
self.base_of_code = self.base_of_code.wrapping_sub(adj_offset);
debug!(
"Relocation Directory fixed up from: 0x{:x} to 0x{:X}",
self.reloc_dir.virtual_address,
self.reloc_dir.virtual_address.wrapping_sub(adj_offset)
);
self.reloc_dir.virtual_address = self.reloc_dir.virtual_address.wrapping_sub(adj_offset);
debug!(
"Debug Directory fixed up from: 0x{:x} to 0x{:X}",
self.debug_dir.virtual_address,
self.debug_dir.virtual_address.wrapping_sub(adj_offset)
);
self.debug_dir.virtual_address = self.debug_dir.virtual_address.wrapping_sub(adj_offset);
}
// Adjust addresses in the section to account for the stripped size
fn fixup_section(section: &mut section_table::SectionTable, adj_offset: u32) {
debug!(
"Section virtual address fixed up from: 0x{:X} to 0x{:X}",
section.virtual_address,
section.virtual_address.wrapping_sub(adj_offset)
);
section.virtual_address = section.virtual_address.wrapping_sub(adj_offset);
if section.pointer_to_linenumbers > 0 {
debug!(
"Section pointer to line numbers fixed up from: 0x{:X} to 0x{:X}",
section.pointer_to_linenumbers,
section.pointer_to_linenumbers.wrapping_sub(adj_offset)
);
section.pointer_to_linenumbers =
section.pointer_to_linenumbers.wrapping_sub(adj_offset);
}
if section.pointer_to_raw_data > 0 {
debug!(
"Section pointer to raw data fixed up from: 0x{:X} to 0x{:X}",
section.pointer_to_raw_data,
section.pointer_to_raw_data.wrapping_sub(adj_offset)
);
section.pointer_to_raw_data = section.pointer_to_raw_data.wrapping_sub(adj_offset);
}
if section.pointer_to_relocations > 0 {
debug!(
"Section pointer to relocations fixed up from: 0x{:X} to 0x{:X}",
section.pointer_to_relocations,
section.pointer_to_relocations.wrapping_sub(adj_offset)
);
section.pointer_to_relocations =
section.pointer_to_relocations.wrapping_sub(adj_offset);
}
}
}
/// Convert machine to str representation. Any case of "COFF_UNKNOWN"
/// should be expected to change to a more specific value.
pub fn machine_to_str(machine: u16) -> &'static str { pub fn machine_to_str(machine: u16) -> &'static str {
// TODO: generate the branches with a macro
match machine { match machine {
COFF_MACHINE_UNKNOWN => "UNKNOWN", COFF_MACHINE_UNKNOWN => "UNKNOWN",
COFF_MACHINE_ALPHA => "ALPHA",
COFF_MACHINE_ALPHA64 => "ALPHA64",
COFF_MACHINE_AM33 => "AM33", COFF_MACHINE_AM33 => "AM33",
// This is an outlier. In the C header, it's IMAGE_FILE_MACHINE_AMD64
COFF_MACHINE_X86_64 => "X86_64", COFF_MACHINE_X86_64 => "X86_64",
COFF_MACHINE_ARM => "ARM", COFF_MACHINE_ARM => "ARM",
COFF_MACHINE_ARM64 => "ARM64", COFF_MACHINE_ARM64 => "ARM64",
COFF_MACHINE_ARMNT => "ARM_NT", COFF_MACHINE_ARMNT => "ARM_NT",
COFF_MACHINE_EBC => "EBC", COFF_MACHINE_EBC => "EBC",
// This is an outlier. In the C header, it's IMAGE_FILE_MACHINE_I386
COFF_MACHINE_X86 => "X86", COFF_MACHINE_X86 => "X86",
COFF_MACHINE_IA64 => "IA64", COFF_MACHINE_IA64 => "IA64",
COFF_MACHINE_LOONGARCH32 => "LOONGARCH32",
COFF_MACHINE_LOONGARCH64 => "LOONGARCH64",
COFF_MACHINE_M32R => "M32R", COFF_MACHINE_M32R => "M32R",
COFF_MACHINE_MIPS16 => "MIPS_16", COFF_MACHINE_MIPS16 => "MIPS_16",
COFF_MACHINE_MIPSFPU => "MIPS_FPU", COFF_MACHINE_MIPSFPU => "MIPS_FPU",

94
third_party/rust/goblin/src/pe/mod.rs поставляемый
Просмотреть файл

@ -15,7 +15,6 @@ pub mod certificate_table;
pub mod characteristic; pub mod characteristic;
pub mod data_directories; pub mod data_directories;
pub mod debug; pub mod debug;
pub mod dll_characteristic;
pub mod exception; pub mod exception;
pub mod export; pub mod export;
pub mod header; pub mod header;
@ -24,7 +23,6 @@ pub mod optional_header;
pub mod options; pub mod options;
pub mod relocation; pub mod relocation;
pub mod section_table; pub mod section_table;
pub mod subsystem;
pub mod symbol; pub mod symbol;
pub mod utils; pub mod utils;
@ -467,98 +465,6 @@ impl<'a> ctx::TryIntoCtx<scroll::Endian> for PE<'a> {
} }
} }
/// An analyzed TE binary
///
/// A TE binary is a PE/PE32+ binary that has had it's header stripped and
/// re-formatted to the TE specification. This presents a challenge for
/// parsing, as all relative addresses (RVAs) are not updated to take this into
/// account, and are thus incorrect. The parsing of a TE must take this into
/// account by using the [header::TeHeader::stripped_size`] field of the TE
/// header to adjust the RVAs during parsing.
#[cfg(feature = "te")]
#[derive(Debug)]
pub struct TE<'a> {
/// The TE header
pub header: header::TeHeader,
/// A list of the sections in this TE binary
pub sections: Vec<section_table::SectionTable>,
/// Debug information, contained in the PE header
pub debug_data: debug::DebugData<'a>,
/// The offset to apply to addresses not parsed by the TE parser
/// itself: [header::TeHeader::stripped_size] - size_of::<[header::TeHeader]>()
pub rva_offset: usize,
}
#[cfg(feature = "te")]
impl<'a> TE<'a> {
/// Reads a TE binary from the underlying `bytes`
pub fn parse(bytes: &'a [u8]) -> error::Result<Self> {
let opts = &options::ParseOptions {
resolve_rva: false,
parse_attribute_certificates: false,
};
let mut offset = 0;
// Parse the TE header and adjust the offsets
let header = header::TeHeader::parse(bytes, &mut offset)?;
let rva_offset = header.stripped_size as usize - core::mem::size_of::<header::TeHeader>();
// Parse the sections and adjust the offsets
let sections = header.sections(bytes, &mut offset)?;
// Parse the debug data. Must adjust offsets before parsing the image_debug_directory
let mut debug_data = debug::DebugData::default();
debug_data.image_debug_directory = debug::ImageDebugDirectory::parse_with_opts(
bytes,
header.debug_dir,
&sections,
0,
opts,
)?;
TE::fixup_debug_data(&mut debug_data, rva_offset as u32);
debug_data.codeview_pdb70_debug_info = debug::CodeviewPDB70DebugInfo::parse_with_opts(
bytes,
&debug_data.image_debug_directory,
opts,
)?;
Ok(TE {
header,
sections,
debug_data,
rva_offset,
})
}
/// Adjust all addresses in the TE binary debug data.
fn fixup_debug_data(dd: &mut debug::DebugData, rva_offset: u32) {
debug!(
"ImageDebugDirectory address of raw data fixed up from: 0x{:X} to 0x{:X}",
dd.image_debug_directory.address_of_raw_data,
dd.image_debug_directory
.address_of_raw_data
.wrapping_sub(rva_offset),
);
dd.image_debug_directory.address_of_raw_data = dd
.image_debug_directory
.address_of_raw_data
.wrapping_sub(rva_offset);
debug!(
"ImageDebugDirectory pointer to raw data fixed up from: 0x{:X} to 0x{:X}",
dd.image_debug_directory.pointer_to_raw_data,
dd.image_debug_directory
.pointer_to_raw_data
.wrapping_sub(rva_offset),
);
dd.image_debug_directory.pointer_to_raw_data = dd
.image_debug_directory
.pointer_to_raw_data
.wrapping_sub(rva_offset);
}
}
/// An analyzed COFF object /// An analyzed COFF object
#[derive(Debug)] #[derive(Debug)]
pub struct Coff<'a> { pub struct Coff<'a> {

Просмотреть файл

@ -1,5 +1,3 @@
//! The module for the PE optional header ([`OptionalHeader`]) and related items.
use crate::container; use crate::container;
use crate::error; use crate::error;
@ -8,125 +6,52 @@ use crate::pe::data_directories;
use scroll::{ctx, Endian, LE}; use scroll::{ctx, Endian, LE};
use scroll::{Pread, Pwrite, SizeWith}; use scroll::{Pread, Pwrite, SizeWith};
/// Standard 32-bit COFF fields (for `PE32`). /// standard COFF fields
///
/// In `winnt.h`, this is a subset of [`IMAGE_OPTIONAL_HEADER32`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32).
///
/// * For 64-bit version, see [`StandardFields64`].
/// * For unified version, see [`StandardFields`].
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct StandardFields32 { pub struct StandardFields32 {
/// See docs for [`StandardFields::magic`](crate::pe::optional_header::StandardFields::magic).
pub magic: u16, pub magic: u16,
/// See docs for [`StandardFields::major_linker_version`].
pub major_linker_version: u8, pub major_linker_version: u8,
/// See docs for [`StandardFields::minor_linker_version`].
pub minor_linker_version: u8, pub minor_linker_version: u8,
/// See docs for [`StandardFields::size_of_code`].
pub size_of_code: u32, pub size_of_code: u32,
/// See docs for [`StandardFields::size_of_initialized_data`].
pub size_of_initialized_data: u32, pub size_of_initialized_data: u32,
/// See docs for [`StandardFields::size_of_uninitialized_data`].
pub size_of_uninitialized_data: u32, pub size_of_uninitialized_data: u32,
/// See docs for [`StandardFields::address_of_entry_point`].
pub address_of_entry_point: u32, pub address_of_entry_point: u32,
/// See docs for [`StandardFields::base_of_code`].
pub base_of_code: u32, pub base_of_code: u32,
/// See docs for [`StandardFields::base_of_data`]. /// absent in 64-bit PE32+
pub base_of_data: u32, pub base_of_data: u32,
} }
/// Convenience constant for `core::mem::size_of::<StandardFields32>()`.
pub const SIZEOF_STANDARD_FIELDS_32: usize = 28; pub const SIZEOF_STANDARD_FIELDS_32: usize = 28;
/// Standard 64-bit COFF fields (for `PE32+`). /// standard 64-bit COFF fields
///
/// In `winnt.h`, this is a subset of [`IMAGE_OPTIONAL_HEADER64`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64).
///
/// * For 32-bit version, see [`StandardFields32`].
/// * For unified version, see [`StandardFields`].
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct StandardFields64 { pub struct StandardFields64 {
/// See docs for [`StandardFields::magic`](crate::pe::optional_header::StandardFields::magic).
pub magic: u16, pub magic: u16,
/// See docs for [`StandardFields::major_linker_version`].
pub major_linker_version: u8, pub major_linker_version: u8,
/// See docs for [`StandardFields::minor_linker_version`].
pub minor_linker_version: u8, pub minor_linker_version: u8,
/// See docs for [`StandardFields::size_of_code`].
pub size_of_code: u32, pub size_of_code: u32,
/// See docs for [`StandardFields::size_of_initialized_data`].
pub size_of_initialized_data: u32, pub size_of_initialized_data: u32,
/// See docs for [`StandardFields::size_of_uninitialized_data`].
pub size_of_uninitialized_data: u32, pub size_of_uninitialized_data: u32,
/// See docs for [`StandardFields::address_of_entry_point`].
pub address_of_entry_point: u32, pub address_of_entry_point: u32,
/// See docs for [`StandardFields::base_of_code`].
pub base_of_code: u32, pub base_of_code: u32,
} }
/// Convenience constant for `core::mem::size_of::<StandardFields64>()`.
pub const SIZEOF_STANDARD_FIELDS_64: usize = 24; pub const SIZEOF_STANDARD_FIELDS_64: usize = 24;
/// Unified 32/64-bit standard COFF fields (for `PE32` and `PE32+`). /// Unified 32/64-bit COFF fields
///
/// Notably, a value of this type is a member of
/// [`goblin::pe::optional_header::OptionalHeader`](crate::pe::optional_header::OptionalHeader),
/// which in turn represents either
/// * [`IMAGE_OPTIONAL_HEADER32`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32); or
/// * [`IMAGE_OPTIONAL_HEADER64`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64)
///
/// from `winnt.h`, depending on the value of [`StandardFields::magic`].
///
/// ## Position in PE binary
///
/// Standard COFF fields are located at the beginning of the [`OptionalHeader`] and before the
/// [`WindowsFields`].
///
/// ## Related structures
///
/// * For 32-bit version, see [`StandardFields32`].
/// * For 64-bit version, see [`StandardFields64`].
#[derive(Debug, PartialEq, Copy, Clone, Default)] #[derive(Debug, PartialEq, Copy, Clone, Default)]
pub struct StandardFields { pub struct StandardFields {
/// The state of the image file. This member can be one of the following values:
///
/// * [`IMAGE_NT_OPTIONAL_HDR32_MAGIC`].
/// * [`IMAGE_NT_OPTIONAL_HDR64_MAGIC`].
/// * [`IMAGE_ROM_OPTIONAL_HDR_MAGIC`].
#[doc(alias = "Magic")]
pub magic: u16, pub magic: u16,
/// The major version number of the linker.
#[doc(alias = "MajorLinkerVersion")]
pub major_linker_version: u8, pub major_linker_version: u8,
/// The minor version number of the linker.
#[doc(alias = "MinorLinkerVersion")]
pub minor_linker_version: u8, pub minor_linker_version: u8,
/// The size of the code section (.text), in bytes, or the sum of all such sections if there are multiple code sections.
#[doc(alias = "SizeOfCode")]
pub size_of_code: u64, pub size_of_code: u64,
/// The size of the initialized data section (.data), in bytes, or the sum of all such sections if there are multiple initialized data sections.
#[doc(alias = "SizeOfInitializedData")]
pub size_of_initialized_data: u64, pub size_of_initialized_data: u64,
/// The size of the uninitialized data section (.bss), in bytes, or the sum of all such sections if there are multiple uninitialized data sections.
#[doc(alias = "SizeOfUninitializedData")]
pub size_of_uninitialized_data: u64, pub size_of_uninitialized_data: u64,
/// A pointer to the entry point function, relative to the image base address.
///
/// * For executable files, this is the starting address.
/// * For device drivers, this is the address of the initialization function.
///
/// The entry point function is optional for DLLs. When no entry point is present, this member is zero.
pub address_of_entry_point: u64, pub address_of_entry_point: u64,
/// A pointer to the beginning of the code section (.text), relative to the image base.
pub base_of_code: u64, pub base_of_code: u64,
/// A pointer to the beginning of the data section (.data), relative to the image base. Absent in 64-bit PE32+. /// absent in 64-bit PE32+
///
/// In other words, it is a Relative virtual address (RVA) of the start of the data (.data) section when the PE
/// is loaded into memory.
// Q (JohnScience): Why is this a u32 and not an Option<u32>?
pub base_of_data: u32, pub base_of_data: u32,
} }
@ -193,217 +118,71 @@ impl From<StandardFields> for StandardFields64 {
} }
} }
/// Standard fields magic number for 32-bit binary (`PE32`). /// Standard fields magic number for 32-bit binary
pub const MAGIC_32: u16 = 0x10b; pub const MAGIC_32: u16 = 0x10b;
/// Standard fields magic number for 64-bit binary (`PE32+`). /// Standard fields magic number for 64-bit binary
pub const MAGIC_64: u16 = 0x20b; pub const MAGIC_64: u16 = 0x20b;
/// Windows specific fields for 32-bit binary (`PE32`). They're also known as "NT additional fields". /// Windows specific fields
///
/// In `winnt.h`, this is a subset of [`IMAGE_OPTIONAL_HEADER32`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32).
///
/// * For 64-bit version, see [`WindowsFields64`].
/// * For unified version, see [`WindowsFields`].
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct WindowsFields32 { pub struct WindowsFields32 {
/// See docs for [`WindowsFields::image_base`].
pub image_base: u32, pub image_base: u32,
/// See docs for [`WindowsFields::section_alignment`].
pub section_alignment: u32, pub section_alignment: u32,
/// See docs for [`WindowsFields::file_alignment`].
pub file_alignment: u32, pub file_alignment: u32,
/// See docs for [`WindowsFields::major_operating_system_version`].
pub major_operating_system_version: u16, pub major_operating_system_version: u16,
/// See docs for [`WindowsFields::minor_operating_system_version`].
pub minor_operating_system_version: u16, pub minor_operating_system_version: u16,
/// See docs for [`WindowsFields::major_image_version`].
pub major_image_version: u16, pub major_image_version: u16,
/// See docs for [`WindowsFields::minor_image_version`].
pub minor_image_version: u16, pub minor_image_version: u16,
/// See docs for [`WindowsFields::major_subsystem_version`].
pub major_subsystem_version: u16, pub major_subsystem_version: u16,
/// See docs for [`WindowsFields::minor_subsystem_version`].
pub minor_subsystem_version: u16, pub minor_subsystem_version: u16,
/// See docs for [`WindowsFields::win32_version_value`].
pub win32_version_value: u32, pub win32_version_value: u32,
/// See docs for [`WindowsFields::size_of_image`].
pub size_of_image: u32, pub size_of_image: u32,
/// See docs for [`WindowsFields::size_of_headers`].
pub size_of_headers: u32, pub size_of_headers: u32,
/// See docs for [`WindowsFields::check_sum`].
pub check_sum: u32, pub check_sum: u32,
/// See docs for [`WindowsFields::subsystem`].
pub subsystem: u16, pub subsystem: u16,
/// See docs for [`WindowsFields::dll_characteristics`].
pub dll_characteristics: u16, pub dll_characteristics: u16,
/// See docs for [`WindowsFields::size_of_stack_reserve`].
pub size_of_stack_reserve: u32, pub size_of_stack_reserve: u32,
/// See docs for [`WindowsFields::size_of_stack_commit`].
pub size_of_stack_commit: u32, pub size_of_stack_commit: u32,
/// See docs for [`WindowsFields::size_of_heap_reserve`].
pub size_of_heap_reserve: u32, pub size_of_heap_reserve: u32,
/// See docs for [`WindowsFields::size_of_heap_commit`].
pub size_of_heap_commit: u32, pub size_of_heap_commit: u32,
/// See docs for [`WindowsFields::loader_flags`].
pub loader_flags: u32, pub loader_flags: u32,
/// See docs for [`WindowsFields::number_of_rva_and_sizes`].
pub number_of_rva_and_sizes: u32, pub number_of_rva_and_sizes: u32,
} }
/// Convenience constant for `core::mem::size_of::<WindowsFields32>()`.
pub const SIZEOF_WINDOWS_FIELDS_32: usize = 68; pub const SIZEOF_WINDOWS_FIELDS_32: usize = 68;
/// Offset of the `check_sum` field in [`WindowsFields32`]. /// Offset of the `check_sum` field in [`WindowsFields32`]
pub const OFFSET_WINDOWS_FIELDS_32_CHECKSUM: usize = 36; pub const OFFSET_WINDOWS_FIELDS_32_CHECKSUM: usize = 36;
/// Windows specific fields for 64-bit binary (`PE32+`). They're also known as "NT additional fields". /// 64-bit Windows specific fields
///
/// In `winnt.h`, this is a subset of [`IMAGE_OPTIONAL_HEADER64`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64).
///
/// *Note: at the moment of writing, [`WindowsFields`] is an alias for `WindowsFields64`. Though [nominally equivalent](https://en.wikipedia.org/wiki/Nominal_type_system),
/// they're semantically distinct.*
///
/// * For 32-bit version, see [`WindowsFields32`].
/// * For unified version, see [`WindowsFields`].
#[repr(C)] #[repr(C)]
#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] #[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)]
pub struct WindowsFields64 { pub struct WindowsFields64 {
/// The *preferred* yet rarely provided address of the first byte of image when loaded into memory; must be a
/// multiple of 64 K.
///
/// This address is rarely used because Windows uses memory protection mechanisms like Address Space Layout
/// Randomization (ASLR). As a result, its rare to see an image mapped to the preferred address. Instead,
/// the Windows PE Loader maps the file to a different address with an unused memory range. This process
/// would create issues because some addresses that would have been constant are now changed. The Loader
/// addresses this via a process called PE relocation which fixes these constant addresses to work with the
/// new image base. The relocation section (.reloc) holds data essential to this relocation process.
/// [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/nt-headers/optional-header/).
///
/// * The default address for DLLs is 0x10000000.
/// * The default for Windows CE EXEs is 0x00010000.
/// * The default for Windows NT, Windows 2000, Windows XP, Windows 95, Windows 98, and Windows Me is 0x00400000.
///
/// ## Position in PE binary
///
/// Windows fields are located inside [`OptionalHeader`] after [`StandardFields`] and before the
/// [`DataDirectories`](data_directories::DataDirectories).
///
/// ## Related structures
///
/// * For 32-bit version, see [`WindowsFields32`].
/// * For unified version, see [`WindowsFields`], especially the note on nominal equivalence.
#[doc(alias = "ImageBase")]
pub image_base: u64, pub image_base: u64,
/// Holds a byte value used for section alignment in memory.
///
/// This value must be greater than or equal to
/// [`file_alignment`](WindowsFields64::file_alignment), which is the next field.
///
/// When loaded into memory, sections are aligned in memory boundaries that are multiples of this value.
///
/// If the value is less than the architectures page size, then the value should match
/// [`file_alignment`](WindowsFields64::file_alignment).
/// [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/nt-headers/optional-header/).
///
/// The default value is the page size for the architecture.
#[doc(alias = "SectionAlignment")]
pub section_alignment: u32, pub section_alignment: u32,
/// The alignment factor (in bytes) that is used to align the raw data of sections in the image file.
///
/// The value should be a power of 2 between 512 and 64 K, inclusive.
///
/// If the [`section_alignment`](WindowsFields64::section_alignment) is less than the architecture's page size,
/// then [`file_alignment`](WindowsFields64::file_alignment) must match [`section_alignment`](WindowsFields64::section_alignment).
///
/// If [`file_alignment`](WindowsFields64::file_alignment) is less than [`section_alignment`](WindowsFields64::section_alignment),
/// then remainder will be padded with zeroes in order to maintain the alignment boundaries.
/// [Source](https://offwhitesecurity.dev/malware-development/portable-executable-pe/nt-headers/optional-header/).
///
/// The default value is 512.
#[doc(alias = "FileAlignment")]
pub file_alignment: u32, pub file_alignment: u32,
/// The major version number of the required operating system.
#[doc(alias = "MajorOperatingSystemVersion")]
pub major_operating_system_version: u16, pub major_operating_system_version: u16,
/// The minor version number of the required operating system.
#[doc(alias = "MinorOperatingSystemVersion")]
pub minor_operating_system_version: u16, pub minor_operating_system_version: u16,
/// The major version number of the image.
#[doc(alias = "MajorImageVersion")]
pub major_image_version: u16, pub major_image_version: u16,
/// The minor version number of the image.
#[doc(alias = "MinorImageVersion")]
pub minor_image_version: u16, pub minor_image_version: u16,
/// The major version number of the subsystem.
#[doc(alias = "MajorSubsystemVersion")]
pub major_subsystem_version: u16, pub major_subsystem_version: u16,
/// The minor version number of the subsystem.
#[doc(alias = "MinorSubsystemVersion")]
pub minor_subsystem_version: u16, pub minor_subsystem_version: u16,
/// Reserved, must be zero.
#[doc(alias = "Win32VersionValue")]
pub win32_version_value: u32, pub win32_version_value: u32,
/// The size (in bytes) of the image, including all headers, as the image is loaded in memory.
///
/// It must be a multiple of the [`section_alignment`](WindowsFields64::section_alignment).
#[doc(alias = "SizeOfImage")]
pub size_of_image: u32, pub size_of_image: u32,
/// The combined size of an MS-DOS stub, PE header, and section headers rounded up to a multiple of
/// [`file_alignment`](WindowsFields64::file_alignment).
#[doc(alias = "SizeOfHeaders")]
pub size_of_headers: u32, pub size_of_headers: u32,
/// The image file checksum. The algorithm for computing the checksum is incorporated into IMAGHELP.DLL.
///
/// The following are checked for validation at load time:
/// * all drivers,
/// * any DLL loaded at boot time, and
/// * any DLL that is loaded into a critical Windows process.
#[doc(alias = "CheckSum")]
pub check_sum: u32, pub check_sum: u32,
/// The subsystem that is required to run this image.
///
/// The subsystem can be one of the values in the [`goblin::pe::subsystem`](crate::pe::subsystem) module.
#[doc(alias = "Subsystem")]
pub subsystem: u16, pub subsystem: u16,
/// DLL characteristics of the image.
///
/// DLL characteristics can be one of the values in the
/// [`goblin::pe::dll_characteristic`](crate::pe::dll_characteristic) module.
#[doc(alias = "DllCharacteristics")]
pub dll_characteristics: u16, pub dll_characteristics: u16,
/// The size of the stack to reserve. Only [`WindowsFields::size_of_stack_commit`] is committed;
/// the rest is made available one page at a time until the reserve size is reached.
///
/// In the context of memory management in operating systems, "commit" refers to the act of allocating physical memory
/// to back a portion of the virtual memory space.
///
/// When a program requests memory, the operating system typically allocates virtual memory space for it. However,
/// this virtual memory space doesn't immediately consume physical memory (RAM) resources. Instead, physical memory
/// is only allocated when the program actually uses (or accesses) that portion of the virtual memory space.
/// This allocation of physical memory to back virtual memory is called "committing" memory.
#[doc(alias = "SizeOfStackReserve")]
pub size_of_stack_reserve: u64, pub size_of_stack_reserve: u64,
/// The size of the stack to commit.
#[doc(alias = "SizeOfStackCommit")]
pub size_of_stack_commit: u64, pub size_of_stack_commit: u64,
/// The size of the local heap space to reserve. Only [`WindowsFields::size_of_heap_commit`] is committed; the rest
/// is made available one page at a time until the reserve size is reached.
#[doc(alias = "SizeOfHeapReserve")]
pub size_of_heap_reserve: u64, pub size_of_heap_reserve: u64,
/// The size of the local heap space to commit.
#[doc(alias = "SizeOfHeapCommit")]
pub size_of_heap_commit: u64, pub size_of_heap_commit: u64,
/// Reserved, must be zero.
#[doc(alias = "LoaderFlags")]
pub loader_flags: u32, pub loader_flags: u32,
/// The number of data-directory entries in the remainder of the optional header. Each describes a location and size.
#[doc(alias = "NumberOfRvaAndSizes")]
pub number_of_rva_and_sizes: u32, pub number_of_rva_and_sizes: u32,
} }
/// Convenience constant for `core::mem::size_of::<WindowsFields64>()`.
pub const SIZEOF_WINDOWS_FIELDS_64: usize = 88; pub const SIZEOF_WINDOWS_FIELDS_64: usize = 88;
/// Offset of the `check_sum` field in [`WindowsFields64`]. /// Offset of the `check_sum` field in [`WindowsFields64`]
pub const OFFSET_WINDOWS_FIELDS_64_CHECKSUM: usize = 40; pub const OFFSET_WINDOWS_FIELDS_64_CHECKSUM: usize = 40;
// /// Generic 32/64-bit Windows specific fields // /// Generic 32/64-bit Windows specific fields
@ -518,57 +297,16 @@ impl TryFrom<WindowsFields64> for WindowsFields32 {
// } // }
// } // }
/// Unified 32/64-bit Windows fields (for `PE32` and `PE32+`). Since 64-bit fields are a superset of 32-bit fields,
/// `WindowsFields` is an alias for `WindowsFields64`.
//
// Opinion (JohnScience): even though they're structurally equivalent, it was a questionable idea to make
// them nominally equivalent as well because they're not actually the same thing semantically. WindowsFields is meant to be
// a unified type that can represent either 32-bit or 64-bit Windows fields.
//
// How do you document this effectively and forward-compatibly? `WindowsFields64` and `WindowsFields` need
// different documentation.
pub type WindowsFields = WindowsFields64; pub type WindowsFields = WindowsFields64;
/// Unified 32/64-bit optional header (for `PE32` and `PE32+`).
///
/// Optional header is the most important of the [NT headers](https://offwhitesecurity.dev/malware-development/portable-executable-pe/nt-headers/).
/// Although it's called "optional", it's actually required for PE image files.
///
/// It is meant to represent either
///
/// * [`IMAGE_OPTIONAL_HEADER32`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32); or
/// * [`IMAGE_OPTIONAL_HEADER64`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64).
///
/// Whether it's 32 or 64-bit is determined by the [`StandardFields::magic`] and by the value
/// [`CoffHeader::size_of_optional_header`](crate::pe::header::CoffHeader::size_of_optional_header).
///
/// ## Position in PE binary
///
/// The optional header is located after [`CoffHeader`](crate::pe::header::CoffHeader) and before
/// section table.
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[doc(alias = "IMAGE_OPTIONAL_HEADER32")]
#[doc(alias = "IMAGE_OPTIONAL_HEADER64")]
pub struct OptionalHeader { pub struct OptionalHeader {
/// Unified standard (COFF) fields. See [`StandardFields`] to learn more.
pub standard_fields: StandardFields, pub standard_fields: StandardFields,
/// Unified Windows fields. See [`WindowsFields`] to learn more.
pub windows_fields: WindowsFields, pub windows_fields: WindowsFields,
/// Data directories. See [`DataDirectories`](data_directories::DataDirectories) to learn more.
pub data_directories: data_directories::DataDirectories, pub data_directories: data_directories::DataDirectories,
} }
/// Magic number for 32-bit binary (`PE32`).
pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC: u16 = 0x10b;
/// Magic number for 64-bit binary (`PE32+`).
pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC: u16 = 0x20b;
/// Magic number for a ROM image.
///
/// More info: <https://superuser.com/questions/156994/what-sort-of-program-has-its-pe-executable-header-set-to-rom-image>.
pub const IMAGE_ROM_OPTIONAL_HDR_MAGIC: u16 = 0x107;
impl OptionalHeader { impl OptionalHeader {
/// Returns the container type of the PE binary.
pub fn container(&self) -> error::Result<container::Container> { pub fn container(&self) -> error::Result<container::Container> {
match self.standard_fields.magic { match self.standard_fields.magic {
MAGIC_32 => Ok(container::Container::Little), MAGIC_32 => Ok(container::Container::Little),

45
third_party/rust/goblin/src/pe/subsystem.rs поставляемый
Просмотреть файл

@ -1,45 +0,0 @@
//! Constants for subsystems required to run image files. These constants are used in the
//! [`goblin::pe::optional_header::WindowsFields::subsystem`](crate::pe::optional_header::WindowsFields::subsystem)
//! field.
/// An unknown subsystem.
pub const IMAGE_SUBSYSTEM_UNKNOWN: u16 = 0;
/// Device drivers and native Windows processes.
pub const IMAGE_SUBSYSTEM_NATIVE: u16 = 1;
/// The Windows graphical user interface (GUI) subsystem.
pub const IMAGE_SUBSYSTEM_WINDOWS_GUI: u16 = 2;
/// The Windows character subsystem.
pub const IMAGE_SUBSYSTEM_WINDOWS_CUI: u16 = 3;
/// The OS/2 character subsystem.
pub const IMAGE_SUBSYSTEM_OS2_CUI: u16 = 5;
/// The Posix character subsystem.
pub const IMAGE_SUBSYSTEM_POSIX_CUI: u16 = 7;
/// Native Win9x driver.
pub const IMAGE_SUBSYSTEM_NATIVE_WINDOWS: u16 = 8;
/// Windows CE.
pub const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: u16 = 9;
/// An Extensible Firmware Interface (EFI) application.
pub const IMAGE_SUBSYSTEM_EFI_APPLICATION: u16 = 10;
/// An EFI driver with boot services.
pub const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: u16 = 11;
/// An EFI driver with run-time services.
pub const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: u16 = 12;
/// An EFI ROM image.
pub const IMAGE_SUBSYSTEM_EFI_ROM: u16 = 13;
/// XBOX.
pub const IMAGE_SUBSYSTEM_XBOX: u16 = 14;
/// Windows boot application.
pub const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION: u16 = 16;

2
third_party/rust/goblin/src/strtab.rs поставляемый
Просмотреть файл

@ -29,7 +29,7 @@ impl<'a> Strtab<'a> {
/// Creates a `Strtab` with `bytes` as the backing string table, using `delim` as the delimiter between entries. /// Creates a `Strtab` with `bytes` as the backing string table, using `delim` as the delimiter between entries.
/// ///
/// NB: this does *not* preparse the string table, which can have non-optimal access patterns. /// NB: this does *not* preparse the string table, which can have non-optimal access patterns.
/// See <https://github.com/m4b/goblin/pull/275> /// See https://github.com/m4b/goblin/pull/275#issue-660364025
pub fn new(bytes: &'a [u8], delim: u8) -> Self { pub fn new(bytes: &'a [u8], delim: u8) -> Self {
Self::from_slice_unparsed(bytes, 0, bytes.len(), delim) Self::from_slice_unparsed(bytes, 0, bytes.len(), delim)
} }

Просмотреть файл

@ -1,24 +0,0 @@
# TE binaries
Binaries located in this directory are precompiled PE32/PE32+ binaries using a
terse executable (TE) header as defined in the Platform Initialization (PI)
specification: [TE](https://uefi.org/specs/PI/1.8/V1_TE_Image.html#te-header).
These binaries were compiled using the
[EDK2](https://github.com/tianocore/edk2) build system.
## test_image.te
This binary is a simple Terse executable binary
## test_image_loaded.bin
This binary is the same as `test_image.te`, but it has been loaded by a loader,
meaning the sections have been placed in the expected address. Please note that
this particular binary has not been relocated, so no relocations have been
applied
## test_image_relocated.bin
This binary is the same as `test_image.te`, but it has been loaded by a loader,
meaning the sections have been placed in the expected address, and any any
relocations have been applied.

Просмотреть файл

@ -1,12 +0,0 @@
[package]
name = "buildid_reader"
version = "0.1.0"
edition = "2021"
[dependencies]
goblin = "^0.8.1"
libc = "0.2"
scroll = "0.12"
log = "0.4"
nsstring = { path = "../../../xpcom/rust/nsstring" }
nserror = { path = "../../../xpcom/rust/nserror" }

Просмотреть файл

@ -1,18 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef buildid_reader_ffi_h
#define buildid_reader_ffi_h
#include "nsString.h"
extern "C" {
nsresult read_toolkit_buildid_from_file(const nsAString* fname,
const nsCString* nname,
nsCString* rv_build_id);
} // extern "C"
#endif // buildid_reader_ffi_h

Просмотреть файл

@ -1,9 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.toolkit.library += [
"buildid_reader_ffi.h",
]

Просмотреть файл

@ -1,44 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::path::Path;
use nserror::{nsresult, NS_OK};
use nsstring::{nsAString, nsCString};
mod reader;
use reader::BuildIdReader;
use log::{error, trace};
#[no_mangle]
pub extern "C" fn read_toolkit_buildid_from_file(
fname: &nsAString,
nname: &nsCString,
rv_build_id: &mut nsCString,
) -> nsresult {
let fname_str = fname.to_string();
let path = Path::new(&fname_str);
let note_name = nname.to_string();
trace!("read_toolkit_buildid_from_file {} {}", fname, nname);
match BuildIdReader::new(&path) {
Ok(mut reader) => match reader.read_string_build_id(&note_name) {
Ok(id) => {
trace!("read_toolkit_buildid_from_file {}", id);
rv_build_id.assign(&id);
NS_OK
}
Err(err) => {
error!("read_toolkit_buildid_from_file failed to read string buiild id from note {:?} with error {:?}", note_name, err);
err
}
},
Err(err) => {
error!("read_toolkit_buildid_from_file failed to build BuildIdReader for {:?} with error {:?}", path, err);
err
}
}
}

Просмотреть файл

@ -1,133 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::ffi::CStr;
use std::fs::File;
use std::io::{Read, Result as IOResult, Seek, SeekFrom};
use std::path::Path;
use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_ERROR_NOT_AVAILABLE, NS_ERROR_OUT_OF_MEMORY};
pub struct BuildIdReader {
file: File,
}
use log::{error, trace};
#[cfg(any(target_os = "android", target_os = "linux"))]
const MAX_BUFFER_READ: usize = std::mem::size_of::<goblin::elf::header::Header>();
#[cfg(target_os = "windows")]
const MAX_BUFFER_READ: usize = std::mem::size_of::<goblin::pe::header::Header>();
#[cfg(any(target_os = "macos", target_os = "ios"))]
const MAX_BUFFER_READ: usize = std::mem::size_of::<goblin::mach::header::Header64>();
impl BuildIdReader {
pub fn new(filename: &Path) -> Result<Self, nsresult> {
trace!("BuildIdReader::new {:?}", filename);
let f = File::open(filename).map_err(|e| {
error!(
"BuildIdReader::new failed to open {:?} with error {}",
filename, e
);
NS_ERROR_INVALID_ARG
})?;
Ok(BuildIdReader { file: f })
}
fn read_raw_build_id(&mut self, note_name: &str) -> Result<Vec<u8>, nsresult> {
trace!("BuildIdReader::read_raw_build_id {}", note_name);
let mut buffer = [0; MAX_BUFFER_READ];
let _ = self.file.read_exact(&mut buffer).map_err(|e| {
error!("BuildIdReader::read_raw_build_id failed to read exact buffer of size {} with error {}", MAX_BUFFER_READ, e);
NS_ERROR_OUT_OF_MEMORY
})?;
// This does actually depend on the platform, so it's not in this
// impl nor source file but in the platform-dependant modules listed at
// the end of this file
self.get_build_id_bytes(&buffer, note_name)
}
pub fn read_string_build_id(&mut self, note_name: &str) -> Result<String, nsresult> {
trace!("BuildIdReader::read_string_build_id {}", note_name);
let b = self.read_raw_build_id(note_name).map_err(|err| {
error!(
"BuildIdReader::read_string_build_id failed to read raw build id with error {}",
err
);
err
})?;
Self::string_from_bytes(&b).ok_or(NS_ERROR_NOT_AVAILABLE)
}
fn string_from_bytes(bytes: &[u8]) -> Option<String> {
trace!("BuildIdReader::string_from_bytes {:?}", bytes);
if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) {
trace!("BuildIdReader::string_from_bytes{:?}", cstr);
if let Ok(s) = cstr.to_str() {
trace!("BuildIdReader::string_from_bytes{}", s);
return Some(s.to_string());
}
}
trace!("BuildIdReader::string_from_bytesNone");
None
}
fn copy_bytes_into(&mut self, offset: usize, buffer: &mut [u8]) -> IOResult<()> {
trace!("BuildIdReader::copy_bytes_into @{}", offset);
self.file.seek(SeekFrom::Start(offset as u64))?;
self.file
.by_ref()
.take(buffer.len() as u64)
.read_exact(buffer)
}
pub fn copy_bytes(&mut self, offset: usize, count: usize) -> IOResult<Vec<u8>> {
trace!("BuildIdReader::copy_bytes @{} : {} bytes", offset, count);
let mut buf = vec![0; count];
self.copy_bytes_into(offset, &mut buf).map_err(|e| {
error!(
"BuildIdReader::copy_bytes failed to copy bytes with error {}",
e
);
e
})?;
Ok(buf)
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
/// SAFETY: Caller need to ensure that `T` is safe to cast to bytes
pub unsafe fn copy<T>(&mut self, offset: usize) -> IOResult<T> {
trace!("BuildIdReader::copy @{}", offset);
self.copy_array(offset, 1)
.map(|v| v.into_iter().next().unwrap())
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
/// SAFETY: Caller need to ensure that `T` is safe to cast to bytes
pub unsafe fn copy_array<T>(&mut self, offset: usize, num: usize) -> IOResult<Vec<T>> {
trace!("BuildIdReader::copy_array @{} : {} num", offset, num);
let mut uninit: Vec<std::mem::MaybeUninit<T>> = Vec::with_capacity(num);
for _ in 0..num {
uninit.push(std::mem::MaybeUninit::uninit());
}
let slice = std::slice::from_raw_parts_mut(
uninit.as_mut_ptr() as *mut u8,
uninit.len() * std::mem::size_of::<T>(),
);
self.copy_bytes_into(offset, slice)?;
std::mem::transmute(uninit)
}
}
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod linux;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub mod macos;

Просмотреть файл

@ -1,129 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use nserror::{
nsresult, NS_ERROR_CANNOT_CONVERT_DATA, NS_ERROR_FAILURE, NS_ERROR_FILE_COPY_OR_MOVE_FAILED,
NS_ERROR_ILLEGAL_VALUE, NS_ERROR_INVALID_ARG, NS_ERROR_INVALID_POINTER, NS_ERROR_NOT_AVAILABLE,
NS_ERROR_NOT_INITIALIZED,
};
use super::BuildIdReader;
use goblin::{elf, elf::note::Note, elf::section_header::SectionHeader};
use scroll::ctx::TryFromCtx;
use log::{error, trace};
impl BuildIdReader {
pub fn get_build_id_bytes(
&mut self,
buffer: &[u8],
note_name: &str,
) -> Result<Vec<u8>, nsresult> {
trace!("get_build_id_bytes: {}", note_name);
let elf_head = elf::Elf::parse_header(buffer).map_err(|e| {
error!(
"get_build_id_bytes: failed to parse Elf header with error {}",
e
);
NS_ERROR_FAILURE
})?;
let mut elf = elf::Elf::lazy_parse(elf_head).map_err(|e| {
error!(
"get_build_id_bytes: failed to lazy parse Elf with error {}",
e
);
NS_ERROR_NOT_INITIALIZED
})?;
trace!("get_build_id_bytes: {:?}", elf);
let context = goblin::container::Ctx {
container: elf.header.container().map_err(|e| {
error!(
"get_build_id_bytes: failed to get Elf container with error {}",
e
);
NS_ERROR_INVALID_ARG
})?,
le: elf.header.endianness().map_err(|e| {
error!(
"get_build_id_bytes: failed to get Elf endianness with error {}",
e
);
NS_ERROR_INVALID_ARG
})?,
};
trace!("get_build_id_bytes: {:?}", context);
let section_header_bytes = self
.copy_bytes(
elf_head.e_shoff as usize,
(elf_head.e_shnum as usize) * (elf_head.e_shentsize as usize),
)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to copy section header bytes with error {}",
e
);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
})?;
trace!("get_build_id_bytes: {:?}", section_header_bytes);
elf.section_headers =
SectionHeader::parse_from(&section_header_bytes, 0, elf_head.e_shnum as usize, context)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to parse sectiion headers with error {}",
e
);
NS_ERROR_INVALID_POINTER
})?;
trace!("get_build_id_bytes: {:?}", elf.section_headers);
let shdr_strtab = &elf.section_headers[elf_head.e_shstrndx as usize];
let shdr_strtab_bytes = self
.copy_bytes(shdr_strtab.sh_offset as usize, shdr_strtab.sh_size as usize)
.map_err(|e| {
error!("get_build_id_bytes: failed to get section header string tab bytes with error {}", e);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
})?;
trace!("get_build_id_bytes: {:?}", shdr_strtab_bytes);
elf.shdr_strtab =
goblin::strtab::Strtab::parse(&shdr_strtab_bytes, 0, shdr_strtab.sh_size as usize, 0x0)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to parse section header string tab with error {}",
e
);
NS_ERROR_ILLEGAL_VALUE
})?;
trace!("get_build_id_bytes: {:?}", elf.shdr_strtab);
let tk_note = elf
.section_headers
.iter()
.find(|s| elf.shdr_strtab.get_at(s.sh_name) == Some(note_name))
.ok_or(NS_ERROR_NOT_AVAILABLE)?;
trace!("get_build_id_bytes: {:?}", tk_note);
let note_bytes = self
.copy_bytes(tk_note.sh_offset as usize, tk_note.sh_size as usize)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to copy bytes for note with error {}",
e
);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
})?;
trace!("get_build_id_bytes: {:?}", note_bytes);
let (note, _size) = Note::try_from_ctx(&note_bytes, (4, context)).map_err(|e| {
error!("get_build_id_bytes: failed to parse note with error {}", e);
NS_ERROR_CANNOT_CONVERT_DATA
})?;
trace!("get_build_id_bytes: {:?}", note);
Ok(note.desc.to_vec())
}
}

Просмотреть файл

@ -1,108 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use nserror::{
nsresult, NS_ERROR_FILE_COPY_OR_MOVE_FAILED, NS_ERROR_ILLEGAL_VALUE, NS_ERROR_INVALID_ARG,
NS_ERROR_INVALID_POINTER, NS_ERROR_INVALID_SIGNATURE, NS_ERROR_NOT_AVAILABLE,
NS_ERROR_NOT_INITIALIZED,
};
use goblin::mach;
use super::BuildIdReader;
use crate::reader::MAX_BUFFER_READ;
use log::{error, trace};
impl BuildIdReader {
pub fn get_build_id_bytes(
&mut self,
buffer: &[u8],
note_name: &str,
) -> Result<Vec<u8>, nsresult> {
trace!("get_build_id_bytes: {}", note_name);
let buf: [u8; MAX_BUFFER_READ] = buffer.try_into().map_err(|e| {
error!(
"get_build_id_bytes: failed to get buffer of {} bytes with error {}",
MAX_BUFFER_READ, e
);
NS_ERROR_NOT_INITIALIZED
})?;
let (section, note) = note_name
.split_once(",")
.ok_or(NS_ERROR_INVALID_SIGNATURE)?;
trace!("get_build_id_bytes: {} {}", section, note);
let macho_head = mach::header::Header64::from_bytes(&buf);
let mut address = MAX_BUFFER_READ;
let end_of_commands = address + (macho_head.sizeofcmds as usize);
while address < end_of_commands {
let command = unsafe {
self.copy::<mach::load_command::LoadCommandHeader>(address as usize)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to load MachO command at {} with error {}",
address, e
);
NS_ERROR_INVALID_ARG
})?
};
trace!("get_build_id_bytes: {:?}", command);
if command.cmd == mach::load_command::LC_SEGMENT_64 {
let segment = unsafe {
self.copy::<mach::load_command::SegmentCommand64>(address as usize)
.map_err(|e| {
error!("get_build_id_bytes: failed to load MachO segment at {} with error {}", address, e);
NS_ERROR_INVALID_POINTER
})?
};
trace!("get_build_id_bytes: {:?}", segment);
let name = segment.name().map_err(|e| {
error!(
"get_build_id_bytes: failed to get segment name with error {}",
e
);
NS_ERROR_ILLEGAL_VALUE
})?;
if name == section {
let sections_addr =
address + std::mem::size_of::<mach::load_command::SegmentCommand64>();
let sections = unsafe {
self.copy_array::<mach::load_command::Section64>(
sections_addr as usize,
segment.nsects as usize,
)
.map_err(|e| {
error!("get_build_id_bytes: failed to get MachO sections at {} with error {}", sections_addr, e);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
})?
};
trace!("get_build_id_bytes: {:?}", sections);
for section in &sections {
trace!("get_build_id_bytes: {:?}", section);
if let Some(sname) = Self::string_from_bytes(&section.sectname) {
if (sname.len() == 0) || (sname != note) {
continue;
}
return self
.copy_bytes(section.addr as usize, section.size as usize)
.map_err(|e| {
error!("get_build_id_bytes: failed to copy section bytes at {} ({} bytes) with error {}", section.addr, section.size, e);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
});
}
}
}
}
address += command.cmdsize as usize;
}
Err(NS_ERROR_NOT_AVAILABLE)
}
}

Просмотреть файл

@ -1,80 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use nserror::{
nsresult, NS_ERROR_FAILURE, NS_ERROR_FILE_COPY_OR_MOVE_FAILED, NS_ERROR_NOT_AVAILABLE,
};
use goblin::pe;
use super::BuildIdReader;
use log::{error, trace};
impl BuildIdReader {
pub fn get_build_id_bytes(
&mut self,
buffer: &[u8],
note_name: &str,
) -> Result<Vec<u8>, nsresult> {
trace!("get_build_id_bytes: {}", note_name);
let pe_head = pe::header::Header::parse(buffer).map_err(|e| {
error!(
"get_build_id_bytes: failed to parse PE buffer with error {}",
e
);
NS_ERROR_FAILURE
})?;
trace!("get_build_id_bytes: {:?}", pe_head);
// Skip the PE header so we can parse the sections
let optional_header_offset = pe_head.dos_header.pe_pointer as usize
+ pe::header::SIZEOF_PE_MAGIC
+ pe::header::SIZEOF_COFF_HEADER;
let sections_offset =
optional_header_offset + pe_head.coff_header.size_of_optional_header as usize;
let sections_size = pe_head.coff_header.number_of_sections as usize
* goblin::pe::section_table::SIZEOF_SECTION_TABLE;
let sections_bytes = self
.copy_bytes(sections_offset, sections_size)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to get sections bytes at {} with error {}",
sections_offset, e
);
NS_ERROR_FAILURE
})?;
trace!("get_build_id_bytes: {:?}", sections_bytes);
let pe_sections = pe_head
.coff_header
.sections(&sections_bytes, &mut 0)
.map_err(|e| {
error!(
"get_build_id_bytes: failed to get PE sections with error {}",
e
);
NS_ERROR_FAILURE
})?;
trace!("get_build_id_bytes: {:?}", pe_sections);
let pe_section = pe_sections
.iter()
.find(|s| s.name().is_ok_and(|name| name == note_name))
.ok_or(NS_ERROR_NOT_AVAILABLE)?;
trace!("get_build_id_bytes: {:?}", pe_section);
self.copy_bytes(
pe_section.pointer_to_raw_data as usize,
pe_section.virtual_size as usize,
)
.map_err(|e| {
error!("get_build_id_bytes: failed to copy PE section bytes at {} ({} bytes) with error {}", pe_section.pointer_to_raw_data, pe_section.virtual_size, e);
NS_ERROR_FILE_COPY_OR_MOVE_FAILED
})
}
}

Просмотреть файл

@ -1,15 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
#ifndef MOZ_BUILDID_SECTION_NAME
#if defined(XP_DARWIN)
# define MOZ_BUILDID_SECTION_NAME "__DATA,mozbuildid"
#elif defined(XP_WIN)
# define MOZ_BUILDID_SECTION_NAME "mozbldid"
#else
# define MOZ_BUILDID_SECTION_NAME ".note.moz.toolkit-build-id"
#endif
#endif // MOZ_BUILDID_SECTION_NAME

Просмотреть файл

@ -20,81 +20,13 @@ def main(output, input_file):
with open(input_file) as fh: with open(input_file) as fh:
objs = [l.strip() for l in fh.readlines()] objs = [l.strip() for l in fh.readlines()]
write_file(output, None) pp = Preprocessor()
pp.out = StringIO()
pp.do_include(os.path.join(buildconfig.topobjdir, "buildid.h"))
buildid = pp.context["MOZ_BUILDID"]
output.write('extern const char gToolkitBuildID[] = "%s";' % buildid)
return set( return set(
os.path.join("build", o) os.path.join("build", o)
for o in objs for o in objs
if os.path.splitext(os.path.basename(o))[0] != "buildid" if os.path.splitext(os.path.basename(o))[0] != "buildid"
) )
def tests(output, buildid):
write_file(output, buildid)
def write_file(output, maybe_buildid):
pp = Preprocessor()
pp.out = StringIO()
pp.do_include(os.path.join(buildconfig.topobjdir, "buildid.h"))
buildid = pp.context["MOZ_BUILDID"] if maybe_buildid is None else maybe_buildid
keyword_extern = "extern" if maybe_buildid is None else ""
attribute_used = "__attribute__((used))" if maybe_buildid is not None else ""
output.write(
"""
#include "buildid_section.h"
#if defined(XP_DARWIN) || defined(XP_WIN)
#define SECTION_NAME_ATTRIBUTE __attribute__((section(MOZ_BUILDID_SECTION_NAME)))
#else
#define SECTION_NAME_ATTRIBUTE
#endif
{extern} const char gToolkitBuildID[] SECTION_NAME_ATTRIBUTE {used} = "{buildid}";
""".format(
extern=keyword_extern,
used=attribute_used,
buildid=buildid,
)
)
if buildconfig.substs.get("TARGET_KERNEL") not in (
"Darwin",
"WINNT",
):
elf_note = """
#include <elf.h>
#define note_name "mzbldid"
#define note_desc "{buildid}"
// This is not defined on Android?
// Android also hardcodes "1"
// https://android.googlesource.com/platform/ndk/+/refs/tags/ndk-r26c/sources/crt/crtbrand.S#35
#ifndef NT_VERSION
#define NT_VERSION 1
#endif
struct note {{
Elf32_Nhdr header; // Elf32 or Elf64 doesn't matter, they're the same size
char name[(sizeof(note_name) + 3) / 4 * 4];
char desc[(sizeof(note_desc) + 3) / 4 * 4];
}};
{extern} const struct note gNoteToolkitBuildID __attribute__((section(MOZ_BUILDID_SECTION_NAME), aligned(4))) {used} = {{
{{ sizeof(note_name), sizeof(note_desc), NT_VERSION }},
note_name,
note_desc
}};
"""
output.write(
"{}".format(
elf_note.format(
extern=keyword_extern,
used=attribute_used,
buildid=buildid,
)
)
)

Просмотреть файл

@ -1,178 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsIFile.h"
#include "nsDirectoryServiceDefs.h"
#include "nsComponentManagerUtils.h"
#include "buildid.h"
#include "buildid_section.h"
#include "mozilla/toolkit/library/buildid_reader_ffi.h"
#include "nsXPCOMPrivate.h"
#include "nsAppRunner.h"
#include <string>
using namespace mozilla;
#define WAIT_FOR_EVENTS \
SpinEventLoopUntil("BuildIDReader::emptyUtil"_ns, [&]() { return done; });
#if defined(XP_WIN)
# define BROKEN_XUL_DLL u"xul_broken_buildid.dll"_ns
# define CORRECT_XUL_DLL u"xul_correct_buildid.dll"_ns
# define MISSING_XUL_DLL u"xul_missing_buildid.dll"_ns
#elif defined(XP_MACOSX)
# define BROKEN_XUL_DLL u"libxul_broken_buildid.dylib"_ns
# define CORRECT_XUL_DLL u"libxul_correct_buildid.dylib"_ns
# define MISSING_XUL_DLL u"libxul_missing_buildid.dylib"_ns
#else
# define BROKEN_XUL_DLL u"libxul_broken_buildid.so"_ns
# define CORRECT_XUL_DLL u"libxul_correct_buildid.so"_ns
# define MISSING_XUL_DLL u"libxul_missing_buildid.so"_ns
#endif
class BuildIDReader : public ::testing::Test {
public:
nsresult getLib(const nsString& lib, nsAutoString& val) {
nsresult rv;
nsCOMPtr<nsIFile> file
#if defined(ANDROID)
= do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
rv = file->InitWithPath(u"/data/local/tmp/test_root/"_ns);
#else
;
rv = NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(file));
#endif
if (!NS_SUCCEEDED(rv)) {
return rv;
}
rv = file->Append(u"gtest"_ns);
if (!NS_SUCCEEDED(rv)) {
return rv;
}
rv = file->Append(lib);
if (!NS_SUCCEEDED(rv)) {
return rv;
}
rv = file->GetPath(val);
return rv;
}
void testFromLib() {}
};
TEST_F(BuildIDReader, ReadCorrectBuildIdFromLib) {
nsAutoString xul;
nsresult rv = getLib(CORRECT_XUL_DLL, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get();
nsCString installedBuildID;
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Error reading from " << NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
EXPECT_EQ(installedBuildID, "12341201987654"_ns);
}
TEST_F(BuildIDReader, ReadIncorrectBuildIdFromLib) {
nsAutoString xul;
nsresult rv = getLib(BROKEN_XUL_DLL, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get();
nsCString installedBuildID;
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Error reading from " << NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
EXPECT_EQ(installedBuildID, "12345678765428Y38AA76"_ns);
}
TEST_F(BuildIDReader, ReadMissingBuildIdFromLib) {
nsAutoString xul;
nsresult rv = getLib(MISSING_XUL_DLL, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get();
nsCString installedBuildID;
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_FALSE(NS_SUCCEEDED(rv))
<< "No error reading from " << NS_ConvertUTF16toUTF8(MISSING_XUL_DLL).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
EXPECT_EQ(installedBuildID, nsCString(""));
EXPECT_EQ(rv, NS_ERROR_NOT_AVAILABLE);
}
TEST_F(BuildIDReader, ReadFromMissingLib) {
nsAutoString xul;
nsresult rv = getLib(u"inexistent-lib.so"_ns, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(CORRECT_XUL_DLL).get();
nsCString installedBuildID;
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_FALSE(NS_SUCCEEDED(rv))
<< "No error reading from " << NS_ConvertUTF16toUTF8(MISSING_XUL_DLL).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
EXPECT_EQ(rv, NS_ERROR_INVALID_ARG);
}
TEST_F(BuildIDReader, ReadFromRealLib) {
nsAutoString xul;
nsresult rv = getLib(XUL_DLL u""_ns, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(XUL_DLL u""_ns).get();
nsCString installedBuildID;
nsCString realMozBuildID(std::to_string(MOZ_BUILDID).c_str());
ASSERT_TRUE(realMozBuildID.Length() == 14);
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Error reading from " << NS_ConvertUTF16toUTF8(XUL_DLL u""_ns).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
EXPECT_EQ(installedBuildID, realMozBuildID);
}
TEST_F(BuildIDReader, ReadFromNSAppRunner) {
nsAutoString xul;
nsresult rv = getLib(XUL_DLL u""_ns, xul);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Unable to find correct lib "
<< NS_ConvertUTF16toUTF8(XUL_DLL u""_ns).get();
nsCString installedBuildID;
nsCString sectionName(MOZ_BUILDID_SECTION_NAME);
rv = read_toolkit_buildid_from_file(&xul, &sectionName, &installedBuildID);
ASSERT_TRUE(NS_SUCCEEDED(rv))
<< "Error reading from " << NS_ConvertUTF16toUTF8(XUL_DLL u""_ns).get()
<< ": " << std::hex << static_cast<uint32_t>(rv);
nsCString realMozBuildID(PlatformBuildID());
ASSERT_TRUE(realMozBuildID.Length() == 14);
EXPECT_EQ(installedBuildID, realMozBuildID);
}

Просмотреть файл

@ -1,21 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FINAL_TARGET = "dist/bin/gtest"
SOURCES = [
"!xul_broken_buildid.c",
]
GeneratedFile(
"xul_broken_buildid.c",
script="../../gen_buildid.py",
entry_point="tests",
inputs=[],
flags=["12345678765428Y38AA76"],
)
SharedLibrary("xul_broken_buildid")

Просмотреть файл

@ -1,21 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FINAL_TARGET = "dist/bin/gtest"
SOURCES = [
"!xul_correct_buildid.c",
]
GeneratedFile(
"xul_correct_buildid.c",
script="../../gen_buildid.py",
entry_point="tests",
inputs=[],
flags=["12341201987654"],
)
SharedLibrary("xul_correct_buildid")

Просмотреть файл

@ -1,13 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
FINAL_TARGET = "dist/bin/gtest"
SOURCES = [
"xul_missing_buildid.c",
]
SharedLibrary("xul_missing_buildid")

Просмотреть файл

@ -1 +0,0 @@
const char gToolkitBuildID[] __attribute((used)) = "12341201987654";

Просмотреть файл

@ -11,20 +11,6 @@ if CONFIG["ENABLE_TESTS"]:
"gkrust-gtest", "gkrust-gtest",
] ]
DIRS += [
"libxul_broken_buildid",
"libxul_correct_buildid",
"libxul_missing_buildid",
]
UNIFIED_SOURCES = [
"TestBuildIDReader.cpp",
]
LOCAL_INCLUDES += [
"/xpcom/build",
]
USE_LIBS += [ USE_LIBS += [
"static:xul", "static:xul",
] ]

Просмотреть файл

@ -139,7 +139,6 @@ if CONFIG["OS_ARCH"] == "WINNT" and CONFIG["CC_TYPE"] not in ("clang", "gcc"):
DIRS += [ DIRS += [
"build", "build",
"buildid_reader",
"gtest", "gtest",
] ]
@ -413,7 +412,3 @@ if CONFIG["COMPILE_ENVIRONMENT"]:
GeneratedFile( GeneratedFile(
"buildid.cpp", script="gen_buildid.py", inputs=["!build/%s.list" % libxul_list] "buildid.cpp", script="gen_buildid.py", inputs=["!build/%s.list" % libxul_list]
) )
EXPORTS += [
"buildid_section.h",
]

Просмотреть файл

@ -43,7 +43,6 @@ data_storage = { path = "../../../../security/manager/ssl/data_storage" }
bitsdownload = { path = "../../../components/bitsdownload", optional = true } bitsdownload = { path = "../../../components/bitsdownload", optional = true }
storage = { path = "../../../../storage/rust" } storage = { path = "../../../../storage/rust" }
bookmark_sync = { path = "../../../components/places/bookmark_sync", optional = true } bookmark_sync = { path = "../../../components/places/bookmark_sync", optional = true }
buildid_reader = { path = "../../buildid_reader" }
chardetng_c = "0.1.1" chardetng_c = "0.1.1"
audio_thread_priority = { version = "0.32", default_features = false } audio_thread_priority = { version = "0.32", default_features = false }
mdns_service = { path="../../../../dom/media/webrtc/transport/mdns_service", optional = true } mdns_service = { path="../../../../dom/media/webrtc/transport/mdns_service", optional = true }

Просмотреть файл

@ -14,7 +14,6 @@ extern crate authrs_bridge;
extern crate bitsdownload; extern crate bitsdownload;
#[cfg(feature = "moz_places")] #[cfg(feature = "moz_places")]
extern crate bookmark_sync; extern crate bookmark_sync;
extern crate buildid_reader;
extern crate cascade_bloom_filter; extern crate cascade_bloom_filter;
extern crate cert_storage; extern crate cert_storage;
extern crate chardetng_c; extern crate chardetng_c;

Просмотреть файл

@ -277,7 +277,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
CXXFLAGS += CONFIG["MOZ_PANGO_CFLAGS"] CXXFLAGS += CONFIG["MOZ_PANGO_CFLAGS"]
DEFINES["TOPOBJDIR"] = TOPOBJDIR DEFINES["TOPOBJDIR"] = TOPOBJDIR
FINAL_TARGET_PP_FILES += ["platform.ini"]
if not CONFIG["MOZ_ARTIFACT_BUILDS"]:
FINAL_TARGET_PP_FILES += ["platform.ini"]
if CONFIG["ENABLE_TESTS"]: if CONFIG["ENABLE_TESTS"]:
DIRS += ["test/gtest"] DIRS += ["test/gtest"]