Skip to content

Missing COFF relocation #7982

@emesare

Description

@emesare
  1. Open thunder rush points valuably
  2. Go to 0x4f062d
  3. Observe zeroed out call to _invalid_parameter_noinfo_noreturn
  4. Relocation information:
>>> bv.relocations_at(0x4f062d + 1)[0]
<Relocation: "_invalid_parameter_noinfo_noreturn" @ 0x60fd00>

Putting this as a bug because IIRC the relocations should be filled in for COFF.

class CoffRelocationHandler: public RelocationHandler
{
public:
virtual bool ApplyRelocation(Ref<BinaryView> view, Ref<Architecture> arch, Ref<Relocation> reloc, uint8_t* dest, size_t len) override
{
// Note: info.base contains preferred base address and the base where the image is actually loaded
(void)view;
(void)arch;
uint64_t* data64 = (uint64_t*)dest;
uint32_t* data32 = (uint32_t*)dest;
uint16_t* data16 = (uint16_t*)dest;
auto info = reloc->GetInfo();
if (len < info.size)
return false;
uint64_t offset = 0;
if (info.pcRelative)
{
int64_t relative_offset = info.target - info.address;
offset = (uint64_t) relative_offset;
}
else
offset = info.target;
if (! info.implicitAddend && info.addend)
offset += info.addend;
if (! info.baseRelative)
offset -= info.base;
switch (info.nativeType)
{
// case PE_IMAGE_REL_I386_SECTION:
case PE_IMAGE_REL_AMD64_SECTION:
// TODO: test this implementation, but for now, just don't warn about it
data16[0] = info.sectionIndex + 1;
break;
// case PE_IMAGE_REL_I386_SECREL:
case PE_IMAGE_REL_AMD64_SECREL:
{
// TODO: test this implementation, but for now, just don't warn about it
auto sections = view->GetSectionsAt(info.target);
if (sections.size() > 0)
{
data32[0] = info.target - sections[0]->GetStart();
}
break;
}
default:
if (info.size == 8)
{
// LogDebug("%s: address: %#" PRIx64 " target: %#" PRIx64 " base: %#" PRIx64 " offset: %#" PRIx64 " current: %#" PRIx64 " result: %#" PRIx64 "", __func__, info.address, info.target, info.base, offset, data64[0], data64[0] + offset);
data64[0] += offset;
}
else if (info.size == 4)
{
// LogDebug("%s: address: %#" PRIx64 " target: %#" PRIx64 " base: %#" PRIx64 " offset: %#" PRIx32 " %+" PRId32 " current: %#" PRIx32 " result: %#" PRIx32 "", __func__, info.address, info.target, info.base, (uint32_t)offset, (uint32_t)offset, data32[0], data32[0] + (uint32_t)offset);
data32[0] += (uint32_t)offset;
}
}
return true;
}
virtual bool GetRelocationInfo(Ref<BinaryView> view, Ref<Architecture> arch, vector<BNRelocationInfo>& result) override
{
(void)arch;
Ref<Logger> logger = view->CreateLogger("X86CoffReloc");
set<uint64_t> relocTypes;
for (auto& reloc : result)
{
if (arch->GetName() == "x86_64")
{
switch (reloc.nativeType)
{
case PE_IMAGE_REL_AMD64_ABSOLUTE:
reloc.type = IgnoredRelocation;
break;
case PE_IMAGE_REL_AMD64_ADDR64:
reloc.baseRelative = true;
reloc.size = 8;
break;
case PE_IMAGE_REL_AMD64_ADDR32NB:
reloc.baseRelative = false;
reloc.size = 4;
break;
case PE_IMAGE_REL_AMD64_ADDR32:
reloc.baseRelative = true;
reloc.size = 4;
break;
case PE_IMAGE_REL_AMD64_REL32_5:
case PE_IMAGE_REL_AMD64_REL32_4:
case PE_IMAGE_REL_AMD64_REL32_3:
case PE_IMAGE_REL_AMD64_REL32_2:
case PE_IMAGE_REL_AMD64_REL32_1:
// LogDebug("%s: %#" PRIx64 "(%#" PRIx64 ")->%#" PRIx64 " %s addend: %ld", __func__, reloc.address, reloc.target, reloc.address - reloc.target, GetRelocationString((COFFx64RelocationType)reloc.nativeType), (long) reloc.addend);
case PE_IMAGE_REL_AMD64_REL32:
// TODO: treat reloc.addend as offset of target from its section (see llvm/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h:67)
reloc.addend = -(4 + (reloc.nativeType - PE_IMAGE_REL_AMD64_REL32));
reloc.baseRelative = false;
reloc.pcRelative = true;
reloc.size = 4;
break;
case PE_IMAGE_REL_AMD64_SECTION:
// The 16-bit section index of the section that contains the target. This is used to support debugging information.
reloc.baseRelative = false;
reloc.size = 2;
reloc.addend = 0;
case PE_IMAGE_REL_AMD64_SECREL:
// TODO: implement these, but for now, just don't warn about them
// The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. reloc.baseRelative = false;
reloc.baseRelative = false;
reloc.size = 4;
reloc.addend = 0;
break;
case PE_IMAGE_REL_AMD64_SECREL7:
// 7-bit offset from the base of the section that contains the target
case PE_IMAGE_REL_AMD64_TOKEN:
case PE_IMAGE_REL_AMD64_SREL32:
case PE_IMAGE_REL_AMD64_PAIR:
case PE_IMAGE_REL_AMD64_SSPAN32:
default:
// By default, PE relocations are correct when not rebased.
// Upon rebasing, support would need to be added to correctly process the relocation
reloc.type = UnhandledRelocation;
relocTypes.insert(reloc.nativeType);
}
for (auto& reloc : relocTypes)
logger->LogWarn("Unsupported COFF relocation: %s", GetRelocationString((COFFx64RelocationType)reloc));
}
else if (arch->GetName() == "x86")
{
switch (reloc.nativeType)
{
case PE_IMAGE_REL_I386_ABSOLUTE:
reloc.type = IgnoredRelocation;
break;
case PE_IMAGE_REL_I386_REL32:
reloc.baseRelative = false;
reloc.pcRelative = true;
reloc.size = 4;
reloc.addend = -4;
break;
case PE_IMAGE_REL_I386_DIR32NB:
reloc.baseRelative = false;
reloc.size = 4;
break;
case PE_IMAGE_REL_I386_DIR32:
reloc.baseRelative = true;
reloc.size = 4;
break;
case PE_IMAGE_REL_I386_SECTION:
// The 16-bit section index of the section that contains the target. This is used to support debugging information.
reloc.baseRelative = false;
reloc.size = 2;
reloc.addend = 0;
case PE_IMAGE_REL_I386_SECREL:
// The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. reloc.baseRelative = false;
reloc.baseRelative = false;
reloc.size = 4;
reloc.addend = 0;
break;
case PE_IMAGE_REL_I386_SEG12:
case PE_IMAGE_REL_I386_TOKEN:
case PE_IMAGE_REL_I386_SECREL7:
case PE_IMAGE_REL_I386_DIR16:
case PE_IMAGE_REL_I386_REL16:
default:
reloc.type = UnhandledRelocation;
relocTypes.insert(reloc.nativeType);
}
for (auto& reloc : relocTypes)
logger->LogWarn("Unsupported COFF relocation: %s", GetRelocationString((COFFx86RelocationType)reloc));
}
}
return true;
}
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    Effort: LowIssues require < 1 week of workImpact: MediumIssue is impactful with a bad, or no, workaround

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions