-
Notifications
You must be signed in to change notification settings - Fork 52
/
sqlite_help.py
185 lines (166 loc) · 5.8 KB
/
sqlite_help.py
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
# Copyright (C) 2014 Dave Lassalle (@superponible) <dave@superponible.com>
# Donated under Volatility Foundation, Inc. Individual Contributor Licensing Agreement
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
@author: Dave Lassalle (@superponible)
@license: GNU General Public License 2.0 or later
@contact: dave@superponible.com
"""
# Helper functions for working with a SQLite database
import struct
import datetime
import math
FORWARD = 1
BACKWARD = -1
def unix_time(dt):
epoch = datetime.datetime.utcfromtimestamp(0)
delta = dt - epoch
return int(delta.total_seconds())
def get_wintime_from_msec(msec):
""" Convert windows epoch time in microseconds to a date string """
seconds, msec= divmod(msec, 1000000)
days, seconds = divmod(seconds, 86400)
if days > 160000 or days < 140000:
days = 0
seconds = 0
msec = 0
return datetime.datetime(1601, 1, 1) + datetime.timedelta(days, seconds, msec)
def get_nixtime_from_sec(sec):
""" Convert unix epoch time in seconds to a date string """
return get_nixtime_from_msec(sec*1000000)
def get_nixtime_from_msec(msec):
""" Convert unix epoch time in microseconds to a date string """
seconds, msec= divmod(msec, 1000000)
days, seconds = divmod(seconds, 86400)
if days > 20000 or days < 9000:
days = 0
seconds = 0
msec = 0
return datetime.datetime(1970, 1, 1) + datetime.timedelta(days, seconds, msec)
def varint_type_to_length(varint):
""" Return the number of bytes used by a varint type """
if varint == 5:
return (6, "")
elif varint == 6 or varint == 7:
return (8, "")
elif varint == 8:
return (0,0)
elif varint == 9:
return (0,1)
else:
return (varint, "")
def ones_comp(bin_str):
""" Return the ones complement of a string of 0s and 1s """
output = ""
for i in bin_str:
if i == '0':
output += '1'
if i == '1':
output += '0'
return output
def find_varint(buff, start, direct):
""" varint are 1-9 bytes, big-endian. The most sig bit is not used, which is why 128 is subtracted
in the for loops below.
See: http://www.evolane.com/support/manuals/shared/manuals/tcltk/sqlite/fileformat.html#varint_format"""
buff_len = len(buff)
varint_len = 1
varint_buff = ""
begin = 0
# at start index and going backwards, so only 1 byte available
if direct == BACKWARD and start == 0:
begin = 0
# going backwards
elif direct == BACKWARD:
# set stopping point, lowest possible is start of the buffer
if start >= 9:
stop = start - 9
else:
stop = 0
for i in range(start, stop, direct):
if ord(buff[i-1]) < 128:
break
if i > stop + 1:
varint_len += 1
begin = start - varint_len + 1
# going forwards
else:
# set a stopping point, maximum length of 9 bytes
if start + 9 > buff_len:
stop = buff_len
else:
stop = start + 9
begin = start
for i in range(start, stop, direct):
if ord(buff[i]) < 128:
break
if i < stop-1:
varint_len += 1
# num_buff contains the varint that was extracted
num_buff = buff[begin:begin+varint_len]
if num_buff == "":
return (-1, 0)
return (varint_to_int(num_buff), varint_len)
def varint_to_int(buff):
""" convert a varint to an integer """
bin_str = ""
varint_len = len(buff)
# convert each byte to a binary string, keeping 7 bytes, unless the buffer is 9 bytes and
# and we are grabbing the last byte, then keep all 8
for i in range(0,varint_len):
if i == 8 and varint_len == 9:
bin_str += bin(ord(buff[i]))[2:].zfill(8)
else:
bin_str += bin(ord(buff[i]))[2:].zfill(8)[1:]
if len(bin_str) == 64 and bin_str[0] == '1':
# negative numbers use all 64 bits and will start with a 1.
# take the ones complement, add 1, then put a negative sign in front
sub_bin_str = ones_comp(bin_str)
value = -(int(sub_bin_str, 2) + 1)
else:
value = int(bin_str, 2)
return value
def varint_to_blob_length(l):
""" Blob field lengths are doubled and 12 is added so that they are even and at least 12 """
if l == 0:
return 0
else:
return (l - 12) / 2
def varint_to_text_length(l):
""" Text field lengths are doubled and 13 is added so that they are odd and at least 13 """
if l == 0:
return 0
else:
return (l - 13) / 2
def sql_unpack(buff):
""" Convert SQL integer bytes into decimal integer """
size = len(buff)
value = ""
if size == 1:
value = struct.unpack(">b", buff)[0]
elif size == 2:
value = struct.unpack(">h", buff)[0]
elif size == 3:
tmp = "\x00" + buff
value = struct.unpack(">l", tmp)[0]
elif size == 4:
value = struct.unpack(">l", buff)[0]
elif size == 6:
tmp = "\x00\x00" + buff
value = struct.unpack(">q", tmp)[0]
elif size == 8:
value = struct.unpack(">q", buff)[0]
return value