CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/source/shellcode/windows/x86/src/hash.py
Views: 11789
1
#!/usr/bin/env python3
2
#=============================================================================#
3
# This script can detect hash collisions between exported API functions in
4
# multiple modules by either scanning a directory tree or just a single module.
5
# This script can also just output the correct hash value for any single API
6
# function for use with the 'api_call' function in 'block_api.asm'.
7
#
8
# Example: Detect fatal collisions against all modules in the C drive:
9
# >hash.py /dir c:\
10
#
11
# Example: List the hashes for all exports from kernel32.dll (As found in 'c:\windows\system32\')
12
# >hash.py /mod c:\windows\system32\ kernel32.dll
13
#
14
# Example: Simply print the correct hash value for the function kernel32.dll!WinExec
15
# >hash.py kernel32.dll WinExec
16
#
17
# Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
18
#=============================================================================#
19
import pefile
20
from sys import path
21
import os
22
import time
23
import sys
24
25
# Modify this path to pefile to suit your machine...
26
pefile_path = 'D:\\Development\\Frameworks\\pefile\\'
27
28
path.append(pefile_path)
29
collisions = [(0x006B8029, 'ws2_32.dll!WSAStartup'),
30
(0xE0DF0FEA, 'ws2_32.dll!WSASocketA'),
31
(0x6737DBC2, 'ws2_32.dll!bind'),
32
(0xFF38E9B7, 'ws2_32.dll!listen'),
33
(0xE13BEC74, 'ws2_32.dll!accept'),
34
(0x614D6E75, 'ws2_32.dll!closesocket'),
35
(0x6174A599, 'ws2_32.dll!connect'),
36
(0x5FC8D902, 'ws2_32.dll!recv'),
37
(0x5F38EBC2, 'ws2_32.dll!send'),
38
39
(0x5BAE572D, 'kernel32.dll!WriteFile'),
40
(0x4FDAF6DA, 'kernel32.dll!CreateFileA'),
41
(0x13DD2ED7, 'kernel32.dll!DeleteFileA'),
42
(0xE449F330, 'kernel32.dll!GetTempPathA'),
43
(0x528796C6, 'kernel32.dll!CloseHandle'),
44
(0x863FCC79, 'kernel32.dll!CreateProcessA'),
45
(0xE553A458, 'kernel32.dll!VirtualAlloc'),
46
(0x300F2F0B, 'kernel32.dll!VirtualFree'),
47
(0x0726774C, 'kernel32.dll!LoadLibraryA'),
48
(0x7802F749, 'kernel32.dll!GetProcAddress'),
49
(0x601D8708, 'kernel32.dll!WaitForSingleObject'),
50
(0x876F8B31, 'kernel32.dll!WinExec'),
51
(0x9DBD95A6, 'kernel32.dll!GetVersion'),
52
(0xEA320EFE, 'kernel32.dll!SetUnhandledExceptionFilter'),
53
(0x56A2B5F0, 'kernel32.dll!ExitProcess'),
54
(0x0A2A1DE0, 'kernel32.dll!ExitThread'),
55
56
(0x6F721347, 'ntdll.dll!RtlExitUserThread'),
57
58
(0x23E38427, 'advapi32.dll!RevertToSelf')
59
]
60
61
collisions_detected = {}
62
modules_scanned = 0
63
functions_scanned = 0
64
65
def ror(dword, bits):
66
return (dword >> bits | dword << (32 - bits)) & 0xFFFFFFFF
67
68
def unicode(string, uppercase=True):
69
result = ''
70
if uppercase:
71
string = string.upper()
72
for c in string:
73
result += c + '\x00'
74
return result
75
76
def hash(module, function, bits=13, print_hash=True):
77
module_hash = 0
78
function_hash = 0
79
for c in unicode(module + '\x00'):
80
module_hash = ror(module_hash, bits)
81
module_hash += ord(c)
82
for c in str(function + b'\x00'):
83
function_hash = ror(function_hash, bits)
84
function_hash += ord(c)
85
h = module_hash + function_hash & 0xFFFFFFFF
86
if print_hash:
87
print('[+] 0x%08X = %s!%s' % (h, module.lower(), function))
88
return h
89
90
def scan(dll_path, dll_name, print_hashes=False, print_collisions=True):
91
global modules_scanned
92
global functions_scanned
93
dll_name = dll_name.lower()
94
modules_scanned += 1
95
pe = pefile.PE(os.path.join(dll_path, dll_name))
96
for export in pe.DIRECTORY_ENTRY_EXPORT.symbols:
97
if export.name is None:
98
continue
99
h = hash(dll_name, export.name, print_hash=print_hashes)
100
for (col_hash, col_name) in collisions:
101
if col_hash == h and col_name != '%s!%s' % (dll_name, export.name):
102
if h not in collisions_detected.keys():
103
collisions_detected[h] = []
104
collisions_detected[h].append(
105
(dll_path, dll_name, export.name))
106
break
107
functions_scanned += 1
108
109
def scan_directory(dir):
110
for dot, dirs, files in os.walk(dir):
111
for file_name in files:
112
if file_name[-4:] == '.dll': # or file_name[-4:] == ".exe":
113
scan(dot, file_name)
114
print('\n[+] Found %d Collisions.\n' % (len(collisions_detected)))
115
for h in collisions_detected.keys():
116
for (col_hash, col_name) in collisions:
117
if h == col_hash:
118
detected_name = col_name
119
break
120
print('[!] Collision detected for 0x%08X (%s):' % (h, detected_name))
121
for (collided_dll_path, collided_dll_name, collided_export_name) in collisions_detected[h]:
122
print('\t%s!%s (%s)' %
123
(collided_dll_name, collided_export_name, collided_dll_path))
124
print('\n[+] Scanned %d exported functions via %d modules.\n' %
125
(functions_scanned, modules_scanned))
126
127
def usage():
128
print(
129
'Usage: hash.py [/dir <path>] | [/mod <path> <module.dll>] | [<module.dll> <function>]')
130
131
132
def main(argv=None):
133
if not argv:
134
argv = sys.argv
135
if len(argv) == 1:
136
usage()
137
else:
138
print('[+] Ran on %s\n' % (time.asctime(time.localtime())))
139
if argv[1] == '/dir':
140
print("[+] Scanning directory '%s' for collisions..." % argv[2])
141
scan_directory(argv[2])
142
elif argv[1] == '/mod':
143
print("[+] Scanning module '%s' in directory '%s'..." %
144
(argv[3], argv[2]))
145
scan(argv[2], argv[3], print_hashes=True)
146
elif len(argv) < 3:
147
usage()
148
else:
149
hash(argv[1], argv[2])
150
151
if __name__ == '__main__':
152
main()
153
154