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
|
#!/usr/bin/python
import struct
import os
import sys
import string
import datetime
import re
#### util
def oldness(f):
if not os.path.exists(f):
return 'file doesn\'t exist'
d = datetime.datetime.now() - datetime.datetime.fromtimestamp(os.stat(f).st_mtime)
if d.days > 0:
s = '%d days' % d.days
elif d.seconds > 3600:
s = '%d hours' % int(d.seconds / 3600)
elif d.seconds > 60:
s = '%d minutes' % int(d.seconds / 60)
s = '%d seconds' % d.seconds
return s, d.seconds
def get_lib(fname, rexp):
l = os.popen('ldd "%s"' % fname).readlines()
refs_raw=[x.split('=>') for x in l if '=>' in x]
refs=[(r[0].strip().split()[0], r[1].strip().split()[0]) for r in refs_raw]
ref = [r[1] for r in refs if re.match(rexp, r[0])]
if len(ref) == 0:
return 'library not found'
return ref[0]
#### small resource parsing library
"""
typedef struct {
DWORD DataSize;
DWORD HeaderSize;
DWORD TYPE;
DWORD NAME;
DWORD DataVersion;
WORD MemoryFlags;
WORD LanguageId;
DWORD Version;
DWORD Characteristics;
} RESOURCEHEADER;
"""
def parse_resource_proper(rsrc):
# http://www.fine-view.com/jp/labs/doc/res32fmt.htm
# TODO
off = 0
def get(d):
l = struct.calcsize(d)
return off + l, struct.unpack(d, rsrc[off:off+l])
# data_size - extra space following header, not including padding
# header_size - size of header structure
# res_type - resource type id (standard or custom)
off, (data_size, header_size) = get('<LL')
return {}
(data_size, header_size, res_type, res_name, data_version,
memory_flags, language_id, version, characteristics
) = struct.unpack(header_def, rsrc[:header_len])
print data_size, header_size, res_type, res_name, data_version
return locals()
printable = set(string.printable)
def looks_like_a_string_key(key):
for key_i in xrange(1, len(key) - 1):
key_subset = set(key[key_i:])
if key_subset <= printable and key[key_i-1] == '\x01':
return key_i
return None
def resource_to_strings(rsrc):
"""
1. split to repeating non zero two byte groups (i.e. utf-16 strings)
2. throw anything of length 1 or 0 (fixes some misses with keys, particularily
CompanyName)
3. go over anything left: a key looks like GGG\x01KKKKKK where G is garbage, K
is an ascii (so in printable). Check bruteforcely. The value is always right after
it.
"""
groups = [[]]
for u in [rsrc[x:x+2] for x in xrange(0,len(rsrc),2)]:
if u == '\x00\x00':
groups.append([])
continue
groups[-1].append(u)
strings = [''.join([a[0] for a in g]) for g in groups if len(g) > 1]
out = {}
ind = 0
#print '\n'.join('%2d: %r' % (i, s) for i, s in enumerate(strings))
while ind < len(strings) - 1:
key = strings[ind]
#print ind, repr(key)
if key == 'VS_VERSION_INFO':
out['VS_VERSION_INFO'] = strings[ind+1]
ind += 2
continue
if set(key) & printable == set():
ind += 1
continue
key_i = looks_like_a_string_key(key)
if key_i:
out[key[key_i:]] = strings[ind + 1]
ind += 2
continue
ind += 1
return out
parse_resource = resource_to_strings
####
try:
import pefile
except:
if os.path.exists('/usr/bin/yum'):
print "please do 'yum install python-pefile'"
else:
print "missing python pefile module"
raise SystemExit
if __name__ == '__main__':
f=sys.argv[-1]
if not os.path.exists(f):
print "%s doesn't exist" % f
raise SystemExit
try:
pe=pefile.PE(f)
except:
print "can't parse pe header - is this a PE file?"
raise SystemExit
rsrc = [s for s in pe.sections if s.Name.startswith('.rsrc\x00')]
if len(rsrc) == 0:
print "missing .rsrc section, no version information in this file"
raise SystemExit
d = parse_resource(rsrc[0].data)
n = max(map(len, d.keys()))
#print '\n'.join('%s: %r' % (k.ljust(n), v) for k,v in d.items())
age_string, age_seconds = oldness(f)
print '%s: FV: %r, PV: %r\nage: %s' % (f, d['FileVersion'], d['ProductVersion'], age_string)
if age_seconds < 60:
sys.exit(0)
sys.exit(1)
|