zipography 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +78 -0
- data/lib.rb +80 -0
- data/zipography-extract +8 -0
- data/zipography-info +12 -0
- data/zipography-inject +10 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1827f4d1fd43192ac37e029981ab04de876a87d8a9e91b044873d671de1738cc
|
4
|
+
data.tar.gz: c2de37c58542aca50915c71712cda9f420cc2dded28cf95a9af1c369465774f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 960794c6d6a3cdb205c54e4b9ef1c38d840ca061e6fd547340c1122c88310312a19f2ff40e481a01d365bc8e76076fe01ee6d8a1fe25e243ce7e086c271fd24a
|
7
|
+
data.tar.gz: 381072f98336e90d7dc953821a7c5812cf736b09a0f19216915acdd5c82a498e7fb1f4e4c911c2519f8222484a26305fbd1becac4ee9fa15907adc61c2a00b66
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# Zipography
|
2
|
+
|
3
|
+
Steganography with zip archives: hide a blob of data within an
|
4
|
+
archive. For typical file archivers (7-zip, WinRAR, File Roller, &c) or
|
5
|
+
file managers (Windows Explorer), the blob is invisible.
|
6
|
+
|
7
|
+
$ gem install zipography
|
8
|
+
|
9
|
+
Limitations:
|
10
|
+
|
11
|
+
* single blob only (but you can just add another .zip as a blob);
|
12
|
+
* doesn't work w/ zip64 files (this means 4GB max for an archive+blob
|
13
|
+
combo);
|
14
|
+
* corrupts zip spec v6.2+ files that use *central directory*
|
15
|
+
encryption;
|
16
|
+
* memory hungry, for it's just a toy, not a serious spy tool.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Say we have a .zip that contains 2 files:
|
21
|
+
|
22
|
+
~~~
|
23
|
+
$ du orig.zip
|
24
|
+
12K orig.zip
|
25
|
+
|
26
|
+
$ bsdtar tf orig.zip
|
27
|
+
The Celebrated Jumping Frog of Calaveras County.txt
|
28
|
+
What You Want.txt
|
29
|
+
~~~
|
30
|
+
|
31
|
+
Inject a picture into the archive:
|
32
|
+
|
33
|
+
$ zipography-inject orig.zip blob1.png > 1.zip
|
34
|
+
|
35
|
+
It it visible? No:
|
36
|
+
|
37
|
+
~~~
|
38
|
+
$ bsdtar tf 1.zip
|
39
|
+
The Celebrated Jumping Frog of Calaveras County.txt
|
40
|
+
What You Want.txt
|
41
|
+
|
42
|
+
$ du 1.zip
|
43
|
+
30K 1.zip
|
44
|
+
~~~
|
45
|
+
|
46
|
+
(`unzip -l` prints the same, but in a much verbose form.)
|
47
|
+
|
48
|
+
Check if we have the picture in the archive:
|
49
|
+
|
50
|
+
~~~
|
51
|
+
$ zipography-info 1.zip
|
52
|
+
Payload size: 18313
|
53
|
+
Adler32: 0x6812d9f
|
54
|
+
Version: 1
|
55
|
+
Valid: true
|
56
|
+
~~~
|
57
|
+
|
58
|
+
Extract it:
|
59
|
+
|
60
|
+
~~~
|
61
|
+
$ zipography-extract 1.zip > 1.png
|
62
|
+
$ xdg-open !$
|
63
|
+
~~~
|
64
|
+
|
65
|
+
<img src='test/blob1.png'>
|
66
|
+
|
67
|
+
## How does it work?
|
68
|
+
|
69
|
+
A blob is injected after a file section right before the 1st *central
|
70
|
+
directory header*. After that, a pointer in an *end of central
|
71
|
+
directory* record is updated to compensate the shift of the *central
|
72
|
+
directory header*.
|
73
|
+
|
74
|
+
<img src='doc/zip.svg'>
|
75
|
+
|
76
|
+
## License
|
77
|
+
|
78
|
+
MIT.
|
data/lib.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'bindata'
|
3
|
+
|
4
|
+
module Zipography
|
5
|
+
|
6
|
+
HEADER_SIZE = 9 # bytes
|
7
|
+
class HiddenBlob < BinData::Record
|
8
|
+
endian :little
|
9
|
+
|
10
|
+
uint32 :checksum
|
11
|
+
uint32 :len
|
12
|
+
uint8 :version, initial_value: 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def checksum s; Zlib.adler32(s); end
|
16
|
+
|
17
|
+
def blob_make file
|
18
|
+
payload = File.read file
|
19
|
+
header = HiddenBlob.new len: File.stat(file).size,
|
20
|
+
checksum: checksum(payload)
|
21
|
+
[payload.force_encoding('ASCII-8BIT'), header.to_binary_s].join
|
22
|
+
end
|
23
|
+
|
24
|
+
class MyZip
|
25
|
+
def initialize file
|
26
|
+
@file = file
|
27
|
+
@buf = File.read file
|
28
|
+
@eocd = end_of_central_dir
|
29
|
+
@first_cdh = first_central_dir_header
|
30
|
+
end
|
31
|
+
|
32
|
+
def first_central_dir_header
|
33
|
+
@buf.index [0x02014b50].pack('V')
|
34
|
+
end
|
35
|
+
|
36
|
+
def end_of_central_dir
|
37
|
+
pos = @buf.rindex [0x06054b50].pack('V')
|
38
|
+
fail 'not a zip file' unless pos
|
39
|
+
pos
|
40
|
+
end
|
41
|
+
|
42
|
+
# start of central dir offset
|
43
|
+
def offset
|
44
|
+
@buf.slice(@eocd+16, 4).unpack('V').first
|
45
|
+
end
|
46
|
+
|
47
|
+
# very crude: instead of an intelligent parsing of eocd, modifying
|
48
|
+
# an offset, replacing eocd, we just change the offset. this won't
|
49
|
+
# fly for zip64 files
|
50
|
+
def repack data
|
51
|
+
[
|
52
|
+
@buf.slice(0, @first_cdh),
|
53
|
+
data,
|
54
|
+
# just before the offset of start of central dir
|
55
|
+
@buf.slice(@first_cdh, (@eocd+16) - @first_cdh),
|
56
|
+
# inject new offset
|
57
|
+
[offset + data.bytesize].pack('V'),
|
58
|
+
# the rest
|
59
|
+
@buf.slice(@eocd+16+4, @buf.size)
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
def blob
|
64
|
+
payload = ''
|
65
|
+
header = {}
|
66
|
+
File.open(@file) do |f|
|
67
|
+
f.seek(offset-HEADER_SIZE)
|
68
|
+
header = HiddenBlob.read f
|
69
|
+
f.seek(offset-HEADER_SIZE-header.len)
|
70
|
+
payload = f.read header.len
|
71
|
+
end
|
72
|
+
{ header: header, payload: payload }
|
73
|
+
end
|
74
|
+
|
75
|
+
def payload_valid? blob
|
76
|
+
blob[:header][:checksum] == checksum(blob[:payload])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/zipography-extract
ADDED
data/zipography-info
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative './lib'
|
4
|
+
include Zipography
|
5
|
+
|
6
|
+
z = MyZip.new ARGV[0]
|
7
|
+
blob = z.blob
|
8
|
+
|
9
|
+
puts "Payload size: #{blob[:header][:len]}"
|
10
|
+
puts "Adler32: 0x" + blob[:header][:checksum].to_i.to_s(16)
|
11
|
+
puts "Version: #{blob[:header][:version]}"
|
12
|
+
puts "Valid: #{z.payload_valid?(blob)}"
|
data/zipography-inject
ADDED
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zipography
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Gromnitsky
|
8
|
+
autorequire:
|
9
|
+
bindir: "."
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bindata
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.4.8
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.4.8
|
27
|
+
description: |
|
28
|
+
Steganography with zip archives: hide a blob of data within an
|
29
|
+
archive. For typical file archivers or file managers, the blob remains
|
30
|
+
invisible.
|
31
|
+
email: alexander.gromnitsky@gmail.com
|
32
|
+
executables:
|
33
|
+
- zipography-extract
|
34
|
+
- zipography-info
|
35
|
+
- zipography-inject
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- "./zipography-extract"
|
40
|
+
- "./zipography-info"
|
41
|
+
- "./zipography-inject"
|
42
|
+
- README.md
|
43
|
+
- lib.rb
|
44
|
+
- zipography-extract
|
45
|
+
- zipography-info
|
46
|
+
- zipography-inject
|
47
|
+
homepage: https://github.com/gromnitsky/zipography
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 2.4.0
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubygems_version: 3.1.2
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: Steganography with zip archives
|
70
|
+
test_files: []
|