-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathentry_point.py
More file actions
executable file
·211 lines (181 loc) · 8.39 KB
/
entry_point.py
File metadata and controls
executable file
·211 lines (181 loc) · 8.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#!/usr/bin/env python3
''' Will disassemble a list of executables at their entry points and ouput to seperate disassembly files. '''
import sys
from capstone import *
from elftools.elf.elffile import ELFFile
# Convert from ELF tools to constants used by Capstone.
decoder_ring = {
'EM_386': CS_ARCH_X86,
'EM_X86_64': CS_ARCH_X86,
'ELFCLASS32': CS_MODE_32,
'ELFCLASS64': CS_MODE_64
}
OUTFILE = "disassembly"
EXT = ".txt"
def main():
# Command line argument error checking.
if(len(sys.argv) < 2):
print("Expected at least one executable (binary file) as an input argument.")
exit()
file_count = 0 # counter for list of command line arguments
for filename in sys.argv[1:]:
file_count += 1 # disassembling the next executable argument
outfile_name = OUTFILE + str(file_count) + EXT # form unique disassembly output file name
print("\nDisassembling: %s..." % filename)
with open(filename, "rb") as f:
# Try to decode as ELF.
try:
elf = ELFFile(f)
except:
print("Could not parse the file as ELF; cannot continue.")
exit()
# Convert and check to see if we support the file.
bits = decoder_ring.get(elf['e_ident']['EI_CLASS'], None)
arch = decoder_ring.get(elf['e_machine'], None)
if arch is None:
print("Unsupported architecture: %s" % elf['e_machine'])
exit()
if bits is None:
print("Unsupported bit width: %s" % elf['e_ident']['EI_CLASS'])
exit()
# Get the .text segment's data.
section_name = ".text"
section = elf.get_section_by_name(section_name)
if not section:
print("No", section_name, "section found in file; file may be stripped or obfuscated.")
exit()
code = section.data()
# Set up options for disassembly of the text segment.
md = Cs(arch, bits)
md.skipdata = True
md.detail = True
# Calculate entry point offset.
top_addr = section.header.sh_addr
entry_point = elf.header.e_entry
offset = entry_point - top_addr
if(offset < 0 or offset >= section.header.sh_size):
print("Entry point is not in", section_name, "section.")
exit()
# Track whether we have found branches.
branches = False
# Disassemble the ELF file.
with open(outfile_name, 'w') as of:
# Print section and program header information.
print("Disassembling: %s...\n" % filename, file=of)
print("-"*50, file=of)
print("Top Address of", section_name, "Section: 0x%x" % top_addr, file=of)
print("\nProgram Entry Point Address: 0x%x" % entry_point, file=of)
print("\nAddress Offset: 0x%x" % offset, file=of)
print("\nSection header for", section_name, ":", section.header, file=of)
print("\nProgram header:", elf.header, "\n", file=of)
print("-"*50, file=of)
# Disassemble at the entry point.
for i in md.disasm(code[offset:], entry_point):
print("0x%x:\t%s\t%s" %(i.address, i.mnemonic, i.op_str), file=of)
if 1 in i.groups or 7 in i.groups:
branches = True
if (len(i.groups) > 0): print("\t\tInstruction group(s):", i.groups, "\n",file=of)
# Indicate if the executable contains instructions from a branch/jump type instruction group.
if branches:
print(filename, "contains branch type instructions.")
if __name__ == "__main__":
main()
'''
-------------------------------------------------
First, install the "pyinstaller" Python library if you want to compile this script into an executable to disassemble.
pip3 install pyinstaller
pyinstaller dist/entry_point/entry_point.py
Executable for entry_point.py is in the dist/entry_point/ directory.
-------------------------------------------------
readelf -h dist/entry_point/entry_point
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x401a45
Start of program headers: 64 (bytes into file)
Start of section headers: 1877768 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 8
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
readelf -s dist/entry_point/entry_point | grep _start
Symbol Table (filtered):
33: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3)
40: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
-------------------------------------------------
readelf -h `which make`
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0xace0
Start of program headers: 64 (bytes into file)
Start of section headers: 221000 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 28
Section header string table index: 27
readelf -s `which make` | grep _start
Symbol Table (filtered):
60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
70: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
125: 0000000000238b38 4 OBJECT GLOBAL DEFAULT 25 commands_started
139: 000000000001c850 246 FUNC GLOBAL DEFAULT 14 output_start
205: 0000000000235000 0 NOTYPE WEAK DEFAULT 24 data_start
207: 000000000000ace0 43 FUNC GLOBAL DEFAULT 14 _start
288: 0000000000235000 0 NOTYPE GLOBAL DEFAULT 24 __data_start
326: 0000000000235e10 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
-------------------------------------------------
readelf -h `which python3`
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x5b2fb0
Start of program headers: 64 (bytes into file)
Start of section headers: 4524728 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 27
Section header string table index: 26
readelf -s `which python3`
Symbol Table (filtered):
55: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
85: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
511: 00000000009b4ea0 0 NOTYPE GLOBAL DEFAULT 23 __data_start
588: 0000000000a50988 0 NOTYPE GLOBAL DEFAULT 24 __bss_start
1044: 000000000063c960 268 OBJECT GLOBAL DEFAULT 15 _Py_startswith__doc__
1251: 00000000005b2fb0 43 FUNC GLOBAL DEFAULT 13 _start
1473: 00000000005b6ab0 17 FUNC GLOBAL DEFAULT 13 _Py_bytes_startswith
1975: 00000000009b4ea0 0 NOTYPE WEAK DEFAULT 23 data_start
2139: 0000000000632010 171 FUNC GLOBAL DEFAULT 13 PyThread_start_new_thread
-------------------------------------------------
'''