Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

71 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ORC (Object Re-Construction)

orc is a CLI utility which parses stripped ELF files and attempts to recreate an approximation of the missing section headers

Background

Since dynamic linking/loading and execution of an ELF binary only requires program headers, the section headers are techincally optional and can be removed.

$ /bin/busybox id
uid=0(root) gid=0(root)
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 0 (bytes into file)
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
$ readelf -S /bin/busybox There are no sections in this file.

However, many tools (e.g. objdump and gdb), depend on the presence of section headers in order to parse and analyze the target ELF file.

$ objdump -d /bin/busybox /bin/busybox: file format elf32-tradbigmips
$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions
All defined functions:
(gdb)

Description

orc parses the program headers and segments of a stripped ELF file and attempts to rebuild the section headers.

$ ./build/orc /bin/busybox 2>/dev/null
$ readelf -h /bin/busybox | grep -i section
Start of section headers: 329384 (bytes into file)
Size of section headers: 40 (bytes)
Number of section headers: 21
Section header string table index: 20
$ readelf -S /bin/busybox There are 21 section headers, starting at offset 0x506a8:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 00400134 000134 00001a 00 A 0 0 1
[ 2] .MIPS.abiflags MIPS_ABIFLAGS 00400150 000150 000018 00 A 0 0 8
[ 3] .dynamic DYNAMIC 00400168 000168 000118 08 A 6 0 4
[ 4] .hash HASH 00400280 000280 00095c 04 A 5 0 4
[ 5] .dynsym DYNSYM 00400bdc 000bdc 0014e0 10 A 6 1 0
[ 6] .dynstr STRTAB 004020bc 0020bc 000a79 00 A 0 0 1
[ 7] .gnu.version VERSYM 00402b36 002b36 00029c 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 00402dd4 002dd4 000050 00 A 6 1 4
[ 9] .rel.dyn REL 00402e24 002e24 000048 08 A 5 0 0
[10] .rel.plt REL 00402e6c 002e6c 0009d0 08 AI 5 14 0
[11] .init PROGBITS 0040383c 00383c 000044 00 AX 0 0 4
[12] .text PROGBITS 00403880 003880 03d7b8 00 AX 0 0 16
[13] .fini PROGBITS 00441038 041038 00dcc8 00 AX 0 0 4
[14] .plt PROGBITS 0044ed00 04ed00 0013c0 00 AX 0 0 32
[15] .got.plt PROGBITS 004600d0 0500d0 0004f0 04 WA 0 0 0
[16] .data PROGBITS 004605c0 0505c0 00001c 00 WA 0 0 16
[17] .rld_map PROGBITS 004605dc 0505dc 000004 00 WA 0 0 4
[18] .got PROGBITS 004605e0 0505e0 000008 04 WAp 0 0 16
[19] .bss NOBITS 004605f0 0505e8 0006d0 00 WA 0 0 16
[20] .shstrtab STRTAB 00000000 050600 0000a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), p (processor specific)

Now objdump is able to parse and disassemble the file:

$ objdump -j .plt -d /bin/busybox | grep -A7 '<getuid@\w*>:'
00450080 <getuid@mips16plt>:
450080:	b203 lw	v0,45008c <getuid@mips16plt+0xc>
450082:	9a60 lw	v1,0(v0)
450084:	651a move	t8,v0
450086:	eb00 jr	v1
450088:	653b move	t9,v1
45008a:	6500 nop
45008c:	0046 05b0 .word	0x4605b0

and gdb can properly resolve the symbols

$ gdb -q /bin/busybox id
0x77f631b0 in ?? ()
(gdb) info functions getuid@mips
All functions matching regular expression "getuid@mips":
Non-debugging symbols:
0x00450081 getuid@mips16plt
(gdb) break getuid@mips16plt
Breakpoint 1 at 0x450081
(gdb) cont
Continuing.
Breakpoint 1, 0x00450081 in getuid@mips16plt ()
(gdb) x/6i $pc
=> 0x450081 <getuid@mips16plt>:	lw	v0,0x45008c <getuid@mips16plt+11>
0x450083 <getuid@mips16plt+2>:	lw	v1,0(v0)
0x450085 <getuid@mips16plt+4>:	move	t8,v0
0x450087 <getuid@mips16plt+6>:	jr	v1
0x450089 <getuid@mips16plt+8>:	move	t9,v1
0x45008b <getuid@mips16plt+10>:	nop

Building

git clone https://github.com/mathewmarcus/orc.git
mkdir build
cd build/
cmake ..
cmake --build .

Usage

./orc [ -S section_headers_csv ] [ -s symbols_csv ] elf-file

Positional Arguments

elf-file

The ELF file to analyze and to which the section headers will be added. Note that this file is modified in-place

Options

-S section_headers_csv

The are some sections which orc may not be able to determine automatically. If information (e.g Name, Type, Offset, etc) about these sections is determined by manual reverse-engineering, it can be manually added to a CSV file, which orc can then parse. The CSV must not include a header file, and each line must match this format - note that fields correspond to the fields of a section header:

Name,Type,Addr (hex),Offset (hex),Size,EntSize,Flags,Link,Info,Alignment

-s symbols_csv

orc can optionally generate .symtab and .strtab sections - which may have be striped away - if information about these specified is specified via a CSV file. The CSV must match this format:

"Name","Location","Function Size""FUN_00506c44","00506c44","24"

Ghidra can be used to create such a CSV file, as described here

Ghidra integration

orc includes a Ghidra script which can be used to generate a CSV containing any/all functions which Ghidra discovers during its analysis of the target ELF.

  1. Copy or link the Ghidra script into one of the Ghidra scripts directories
    $ ln -s `realpath ./scripts/ExportMIPS16Symbols.py`~/ghidra_scripts/
  2. Open the Ghidra Script Manager window:
  3. Click Refresh Script List
  4. In the left navbar, find and run the MIPS/ExportMIPS16Symbols.py script, which will allow you to specify an output CSV into which the Ghidra-parsed function symbols will be saved.

This CSV file can now be used in the orc invocation as described here

TODO:

  • add support for other architectures/platforms besides MIPS
  • support for parsing additional section headers
  • code cleanup
  • unit tests

About

reconstruct section headers in stripped ELF objects

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages