summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoritsme <itsme@xs4all.nl>2021-07-06 22:50:59 +0200
committeritsme <itsme@xs4all.nl>2021-07-06 22:50:59 +0200
commitae5362ee71880cee2a986da15b47a5aa4c4368ce (patch)
tree259db509dcfb54d30d3e9f1f3c4f1e248d093996
parente9e4b7a5d53ca044f5efd325b9d25d2c72b1a2dc (diff)
crodump: added verbose dump, which prints all unreferenced datablocks. added --increment to scan for KOD shifts. support hex stdin data. added --struonly option.
-rw-r--r--crodump.py74
-rw-r--r--hexdump.py9
2 files changed, 72 insertions, 11 deletions
diff --git a/crodump.py b/crodump.py
index a2a94a1..1ba7e5e 100644
--- a/crodump.py
+++ b/crodump.py
@@ -1,13 +1,23 @@
1import os.path 1import os.path
2import io
2import struct 3import struct
3from binascii import b2a_hex 4from binascii import b2a_hex
4from hexdump import hexdump, asasc, tohex 5from hexdump import hexdump, asasc, tohex, unhex
5from koddecoder import kodecode 6from koddecoder import kodecode
6""" 7"""
7python3 crodump.py crodump chechnya_proverki_ul_2012 8python3 crodump.py crodump chechnya_proverki_ul_2012
8python3 crodump.py kodump -s 6 -o 0x4cc9 -e 0x5d95 chechnya_proverki_ul_2012/CroStru.dat 9python3 crodump.py kodump -s 6 -o 0x4cc9 -e 0x5d95 chechnya_proverki_ul_2012/CroStru.dat
9""" 10"""
10 11
12def enumunreferenced(ranges, filesize):
13 o = 0
14 for start, end, desc in sorted(ranges):
15 if start > o:
16 yield o, start-o
17 o = end
18 if o<filesize:
19 yield o, filesize-o
20
11class Datafile: 21class Datafile:
12 def __init__(self, dat, tad): 22 def __init__(self, dat, tad):
13 self.dat = dat 23 self.dat = dat
@@ -15,6 +25,9 @@ class Datafile:
15 25
16 self.readtad() 26 self.readtad()
17 27
28 self.dat.seek(0, io.SEEK_END)
29 self.datsize = self.dat.tell()
30
18 def readtad(self): 31 def readtad(self):
19 self.tad.seek(0) 32 self.tad.seek(0)
20 hdrdata = self.tad.read(2*4) 33 hdrdata = self.tad.read(2*4)
@@ -28,21 +41,37 @@ class Datafile:
28 41
29 def dump(self, args, dokodecode=False, plainbytes=0): 42 def dump(self, args, dokodecode=False, plainbytes=0):
30 print("tadhdr: %08x %08x" % tuple(self.tadhdr)) 43 print("tadhdr: %08x %08x" % tuple(self.tadhdr))
44 ranges = []
31 for i, (ofs, ln, chk) in enumerate(self.tadidx): 45 for i, (ofs, ln, chk) in enumerate(self.tadidx):
32 if ln==0xFFFFFFFF: 46 if ln==0xFFFFFFFF:
33 print("%5d: %08x %08x %08x" % (i, ofs, ln, chk)) 47 print("%5d: %08x %08x %08x" % (i, ofs, ln, chk))
34 continue 48 continue
35 flags = ln>>24 49 flags = ln>>24
50
36 ln &= 0xFFFFFFF 51 ln &= 0xFFFFFFF
37 dat = self.readdata(ofs, ln) 52 dat = self.readdata(ofs, ln)
38 plain = b'' 53 plain = b''
54 decrypted = ' '
39 if dokodecode and not args.nokod: 55 if dokodecode and not args.nokod:
40 plain = dat[:plainbytes] 56 pb = plainbytes if flags else 8
41 dat = kodecode(i+1, dat[plainbytes:]) 57 plain = dat[:pb]
58 dat = kodecode(i+1, dat[pb:])
59 decrypted = '*' if flags else '+'
42 if args.ascdump: 60 if args.ascdump:
43 print("%5d: %08x-%08x: (%02x:%08x) %s %s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), asasc(dat))) 61 print("%5d: %08x-%08x: (%02x:%08x) %s %s%s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), decrypted, asasc(dat)))
44 else: 62 else:
45 print("%5d: %08x-%08x: (%02x:%08x) %s %s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), tohex(dat))) 63 print("%5d: %08x-%08x: (%02x:%08x) %s %s%s" % (i, ofs, ofs+ln, flags, chk, tohex(plain), decrypted, tohex(dat)))
64 ranges.append((ofs, ofs+ln, "item #%d" % i))
65
66 if args.verbose:
67 # output parts not referenced in the .tad file.
68 for o, l in enumunreferenced(ranges, self.datsize):
69 dat = self.readdata(o, l)
70 if args.ascdump:
71 print("%08x-%08x: %s" % (o, o+l, asasc(dat)))
72 else:
73 print("%08x-%08x: %s" % (o, o+l, tohex(dat)))
74
46 75
47class Database: 76class Database:
48 def __init__(self, dbdir): 77 def __init__(self, dbdir):
@@ -62,6 +91,12 @@ class Database:
62 def getname(self, name, ext): 91 def getname(self, name, ext):
63 return os.path.join(self.dbdir, "Cro%s.%s" % (name, ext)) 92 return os.path.join(self.dbdir, "Cro%s.%s" % (name, ext))
64 93
94def incdata(data, s):
95 """
96 add 's' to each byte.
97 This is useful for finding the correct shift from an incorrectly shifted chunk.
98 """
99 return b"".join(struct.pack("<B", (_+s)&0xFF) for _ in data)
65 100
66def decode_kod(args, data): 101def decode_kod(args, data):
67 """ 102 """
@@ -75,6 +110,17 @@ def decode_kod(args, data):
75 args.shift = int(args.shift, 0) 110 args.shift = int(args.shift, 0)
76 enc = kodecode(args.shift, data) 111 enc = kodecode(args.shift, data)
77 hexdump(args.offset, enc) 112 hexdump(args.offset, enc)
113 elif args.increment:
114 # explicitly specified shift.
115 for s in range(256):
116 enc = incdata(data, s)
117 if args.ascdump:
118 print("%02x: %s" % (s, asasc(enc)))
119 else:
120 print("%02x: %s" % (s, tohex(enc)))
121
122
123
78 else: 124 else:
79 # output with all possible 'shift' values. 125 # output with all possible 'shift' values.
80 for s in range(256): 126 for s in range(256):
@@ -106,6 +152,8 @@ def kod_hexdump(args):
106 # no filename -> read from stdin. 152 # no filename -> read from stdin.
107 import sys 153 import sys
108 data = sys.stdin.buffer.read() 154 data = sys.stdin.buffer.read()
155 if args.unhex:
156 data = unhex(data)
109 decode_kod(args, data) 157 decode_kod(args, data)
110 158
111 159
@@ -115,6 +163,8 @@ def cro_dump(args):
115 if db.stru: 163 if db.stru:
116 print("stru") 164 print("stru")
117 db.stru.dump(args, dokodecode=True) 165 db.stru.dump(args, dokodecode=True)
166 if args.struonly:
167 return
118 if db.index: 168 if db.index:
119 print("index") 169 print("index")
120 db.index.dump(args) 170 db.index.dump(args)
@@ -132,20 +182,24 @@ def main():
132 subparsers = parser.add_subparsers() 182 subparsers = parser.add_subparsers()
133 parser.set_defaults(handler=None) 183 parser.set_defaults(handler=None)
134 184
135 ko = subparsers.add_parser('kodump', help='KOD dumper') 185 ko = subparsers.add_parser('kodump', help='KOD/hex dumper')
136 ko.add_argument('--offset', '-o', type=str, default="0") 186 ko.add_argument('--offset', '-o', type=str, default="0")
137 ko.add_argument('--length', '-l', type=str) 187 ko.add_argument('--length', '-l', type=str)
138 ko.add_argument('--endofs', '-e', type=str) 188 ko.add_argument('--endofs', '-e', type=str)
139 ko.add_argument('--shift', '-s', type=str) 189 ko.add_argument('--unhex', '-x', action='store_true', help="assume the input contains hex data")
140 ko.add_argument('--ascdump', '-a', action='store_true') 190 ko.add_argument('--shift', '-s', type=str, help="KOD decode with the specified shift")
141 ko.add_argument('--nokod', '-n', action='store_true') 191 ko.add_argument('--increment', '-i', action='store_true', help="assume data is already KOD decoded, but with wrong shift -> dump alternatives.")
142 ko.add_argument('filename', type=str, nargs='?') 192 ko.add_argument('--ascdump', '-a', action='store_true', help="CP1251 asc dump of the data")
193 ko.add_argument('--nokod', '-n', action='store_true', help="don't KOD decode")
194 ko.add_argument('filename', type=str, nargs='?', help="dump either stdin, or the specified file")
143 ko.set_defaults(handler=kod_hexdump) 195 ko.set_defaults(handler=kod_hexdump)
144 196
145 cro = subparsers.add_parser('crodump', help='CROdumper') 197 cro = subparsers.add_parser('crodump', help='CROdumper')
198 cro.add_argument('--verbose', '-v', action='store_true')
146 cro.add_argument('--kodecode', '-k', action='store_true') 199 cro.add_argument('--kodecode', '-k', action='store_true')
147 cro.add_argument('--ascdump', '-a', action='store_true') 200 cro.add_argument('--ascdump', '-a', action='store_true')
148 cro.add_argument('--nokod', '-n', action='store_true') 201 cro.add_argument('--nokod', '-n', action='store_true')
202 cro.add_argument('--struonly', action='store_true')
149 cro.add_argument('dbdir', type=str) 203 cro.add_argument('dbdir', type=str)
150 cro.set_defaults(handler=cro_dump) 204 cro.set_defaults(handler=cro_dump)
151 205
diff --git a/hexdump.py b/hexdump.py
index c119b16..aeb8c88 100644
--- a/hexdump.py
+++ b/hexdump.py
@@ -1,9 +1,16 @@
1import struct 1import struct
2from binascii import b2a_hex 2from binascii import b2a_hex, a2b_hex
3""" 3"""
4Simple hexdump, 16 bytes per line with offset. 4Simple hexdump, 16 bytes per line with offset.
5""" 5"""
6 6
7def unhex(data):
8 if type(data)==bytes:
9 data = data.decode('ascii')
10 data = data.replace(' ', '')
11 data = data.strip()
12 return a2b_hex(data)
13
7def ashex(line): 14def ashex(line):
8 return " ".join("%02x" % _ for _ in line) 15 return " ".join("%02x" % _ for _ in line)
9def aschr(b): 16def aschr(b):