avast / retdec

RetDec is a retargetable machine-code decompiler based on LLVM.
https://retdec.com/
MIT License
7.98k stars 944 forks source link

UPX unpacker crash: corrupted double-linked list #120

Open PeterMatula opened 6 years ago

PeterMatula commented 6 years ago

Unpacking of this file crashes.

Command:

retdec-unpacker a7a112bae60ba29dfc89f681f8106bb5c340fa734631eff6141d336af07e9b7f

Output:

[UPX] Detected NRV2E unpacking stub based on signature & metadata.
[UPX] Started unpacking of file 'A7A112BAE60BA29DFC89F681F8106BB5C340FA734631EFF6141D336AF07E9B7F.dat'.
[UPX] Detected filter 0x26 with parameter 0x11 based on signature.
[UPX] Unpacked data based on UPX metadata.
[UPX] Original header found at address 0x95b9f in extra data.
[UPX] Import hints address 0x94000 found in extra data.
[UPX] Original entry point address set to 0x54d5d.
[UPX] Original resources directory found at RVA 0x8d000 with size 0x68000.
corrupted double-linked list
Aborted (core dumped)

First problem in valgrind:

[UPX] Import hints address 0x94000 found in extra data.
Invalid read of size 4
   at 0x6BB2048: preprocessing::unpacker::upx::PeUpxStub<32>::fixSizeOfSections(...) (pe_upx_stub.cpp:478)
   by 0x6BC0035: preprocessing::unpacker::upx::PeUpxStub<32>::unpack(std::string const&) (pe_upx_stub.cpp:215)
   by 0x6BC3EFE: preprocessing::unpacker::upx::UpxPlugin::unpack() (upx.cpp:104)
   by 0x314335: run (plugin.h:158)
   by 0x314335: unpackFile(...) (unpacker.cpp:93)
   by 0x3155F3: processArgs(...) (unpacker.cpp:157)
   by 0x2F058D: main (unpacker.cpp:202)
 Address 0x93709dc is 12 bytes after a block of size 192 alloc'd
   at 0x4C2D52F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
   by 0x482A48: allocate (new_allocator.h:111)
   by 0x482A48: allocate (alloc_traits.h:436)
   by 0x482A48: _M_allocate (stl_vector.h:172)
   by 0x482A48: void std::vector<...>::_M_realloc_insert<...>(...) (vector.tcc:406)
   by 0x483235: push_back (stl_vector.h:948)
   by 0x483235: PeLib::PeHeaderT<32>::readSections(...) const (PeHeader.h:1070)
   by 0x483523: PeLib::PeHeaderT<32>::read(...) (PeHeader.h:1113)
   by 0x483879: PeLib::PeFileT<32>::readPeHeader() (PeFile.h:317)
   by 0x6BBFF71: preprocessing::unpacker::upx::PeUpxStub<32>::unpack(std::string const&) (pe_upx_stub.cpp:197)
   by 0x6BC3EFE: preprocessing::unpacker::upx::UpxPlugin::unpack() (upx.cpp:104)
   by 0x314335: run (plugin.h:158)
   by 0x314335: unpackFile(...) (unpacker.cpp:93)
   by 0x3155F3: processArgs(...) (unpacker.cpp:157)
   by 0x2F058D: main (unpacker.cpp:202)
s3rvac commented 6 years ago

I analyzed the problem. PeUpxStub<bits>::fixSizeOfSections() in src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp contains the following line:

478      _newPeFile->peHeader().setVirtualAddress(_upx0Sect->getSecSeg()->getIndex() + 1, _newPeFile->peHeader().getVirtualAddress(_upx0Sect->getSecSeg()->getIndex() + 1) + diff);

The _newPeFile->peHeader().setVirtualAddress() call calls PeHeaderT<x>::getVirtualAddress(), which comes from pelib/include/pelib/PeHeader.h:

2195     template<int x>
2196     dword PeHeaderT<x>::getVirtualAddress(word wSectionnr) const
2197     {
2198         return m_vIsh[wSectionnr].VirtualAddress;
2199     }

In that call, the value of wSectionnr is 4. However, m_vIsh.size() is also 4, which causes an out-of-bounds read from invalid memory (the only valid indexes are 0 through 3).