Browse Source

Fix (frequent) bit ordering issue when extracting some JPGs

pull/54/head
coomdev 2 years ago
parent
commit
ea0502858d
  1. 2
      README.md
  2. 108
      chrome/dist/main.js
  3. 2
      chrome/manifest.json
  4. 108
      dist/main.js
  5. 108
      firefox/dist/main.js
  6. 2
      firefox/manifest.json
  7. 2
      firefox_update.json
  8. 2
      main.meta.js
  9. 110
      main.user.js
  10. BIN
      pngextraembedder-0.314.xpi
  11. 101
      src/f5stego.ts
  12. 28
      src/main.ts

2
README.md

@ -26,7 +26,7 @@ Also, use this if you plan to use b4k's archive.
- [Install 4chanX (recommended)](https://www.4chan-x.net/builds/4chan-X.user.js)
- [Install JKCS (recommended)](https://git.coom.tech/araragi/JKCS/src/branch/master/README.md)
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.313.xpi) or Chrome-based (Down for "maintainance"))
- Install the correct WebExtension for your Browser ([Firefox](https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.314.xpi) or Chrome-based (Down for "maintainance"))
For FF users, the extension is signed so you can just drag and drop it on your about:addons tab.

108
chrome/dist/main.js

File diff suppressed because one or more lines are too long

2
chrome/manifest.json

@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!",
"version": "0.313",
"version": "0.314",
"icons": {
"64": "1449696017588.png"
},

108
dist/main.js

File diff suppressed because one or more lines are too long

108
firefox/dist/main.js

File diff suppressed because one or more lines are too long

2
firefox/manifest.json

@ -7,7 +7,7 @@
},
"name": "PngExtraEmbedder",
"description": "Discover embedded files on 4chan and archives!",
"version": "0.313",
"version": "0.314",
"icons": {
"64": "1449696017588.png"
},

2
firefox_update.json

@ -1 +1 @@
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.313","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.313.xpi"}]}}}
{"addons":{"{34ac4994-07f2-44d2-8599-682516a6c6a6}":{"updates":[{"version":"0.314","update_link":"https://git.coom.tech/fuckjannies/lolipiss/raw/branch/%E4%B8%AD%E5%87%BA%E3%81%97/pngextraembedder-0.314.xpi"}]}}}

2
main.meta.js

@ -1,7 +1,7 @@
// ==UserScript==
// @name PNGExtraEmbed
// @namespace https://coom.tech/
// @version 0.313
// @version 0.314
// @description uhh
// @author You
// @match https://boards.4channel.org/*

110
main.user.js

File diff suppressed because one or more lines are too long

BIN
pngextraembedder-0.314.xpi

Binary file not shown.

101
src/f5stego.ts

@ -1,4 +1,3 @@
/* eslint-disable no-constant-condition */
/* This software is licensed under the MIT License.
Copyright (c) 2016 desudesutalk
@ -112,7 +111,7 @@ import { BitstreamWriter, revbyte } from "./bitstream";
// Standard Huffman tables for coder initialization
// ===========================================================================================================
function* f5get(): Generator<void, Buffer, number> {
function* f5get() {
let extrBit = 0;
//var pm = this.#stegShuffle(coeff),
@ -132,7 +131,8 @@ function* f5get(): Generator<void, Buffer, number> {
let len = 0;
while (toread--) {
len = len * 2 + (yield);
const b = (yield);
len = len * 2 + b;
}
const b = yield;
toread += 8;
@ -141,12 +141,13 @@ function* f5get(): Generator<void, Buffer, number> {
else
len *= 2;
while (toread--) {
len = len * 2 + (yield);
const b = (yield);
len = len * 2 + b;
}
let rlen = revbyte(len, b ? 23 : 16);
const rlen = revbyte(len, b ? 23 : 16);
len = rlen;
if (len >= 256) // don't know if length decoding is correct so let's be safe and trim
len = rlen = 256;
if (len > 256)
throw new Error("Too big for Smash");
len *= 8; // bytes to bits
// k must be 1
const chunks: Uint8Array[] = [];
@ -348,7 +349,7 @@ export class f5stego {
_examined = 0,
_thrown = 0,
shuffled_index = 0,
i, ii: number;
i, n, ii: number;
//let { gamma, pm } = this.#stegShuffle(coeff_count);
//let gammaI = 0;
@ -358,7 +359,7 @@ export class f5stego {
data_idx = 0,
available_bits_to_embed = 0;
const n = (1 << k) - 1;
n = (1 << k) - 1;
byte_to_embed = k - 1;
byte_to_embed ^= 0; // nop
@ -447,8 +448,8 @@ export class f5stego {
_examined += n;
while (true) {
let vhash = 0;
let extracted_bit;
var vhash = 0,
extracted_bit;
for (i = 0; i < code_word.length; i++) {
if (coeff[code_word[i]] > 0) {
@ -564,21 +565,21 @@ export class f5stego {
coeff.set(comp.blocks);
let pos = -1,
extrBit = 0;
const cCount = coeff.length - 1;
extrBit = 0,
cCount = coeff.length - 1;
//var pm = this.#stegShuffle(coeff),
// gamma = pm.gamma,
// gammaI = 0;
let k = 0;
let n, k = 0;
const out = new Uint8Array((coeff.length / 8) | 0);
let extrByte = 0;
let outPos = 0;
let bitsAvail = 0;
let code = 0;
let hash = 0;
let out = new Uint8Array((coeff.length / 8) | 0),
extrByte = 0,
outPos = 0,
bitsAvail = 0,
code = 0,
hash = 0;
while (bitsAvail < 4) {
pos++;
@ -598,7 +599,7 @@ export class f5stego {
//k = (k ^ gamma[gammaI++] & 15) + 1;
k = (k & 15) + 1;
const n = (1 << k) - 1;
n = (1 << k) - 1;
bitsAvail = 0;
@ -677,15 +678,15 @@ export class f5stego {
return out.subarray(s, s + l);
}
gengen!: Generator<void, Buffer, number>;
gengen: Generator<void, Buffer, number>;
parse(data: Uint8Array, tolerant = false) {
let offset = 0;
function _buildHuffmanTable(nrcodes: Uint8Array, values: Uint8Array) {
let codevalue = 0;
let pos_in_table = 0;
const HT = new Uint16Array(65536);
let codevalue = 0,
pos_in_table = 0,
HT = new Uint16Array(65536);
for (let k = 0; k < 16; k++) {
for (let j = 0; j < nrcodes[k]; j++) {
for (let i = codevalue << (15 - k), cntTo = ((codevalue + 1) << (15 - k)); i < cntTo; i++) {
@ -709,13 +710,14 @@ export class f5stego {
successivePrev: number,
successive: number) => {
const startOffset = offset;
let bitsData = 0,
let startOffset = offset,
bitsData = 0,
bitsCount = 0,
eobrun = 0;
const p1 = 1 << successive; /* 1 in the bit position being coded */
const m1 = -1 << successive; /* -1 in the bit position being coded */
eobrun = 0,
p1 = 1 << successive, /* 1 in the bit position being coded */
m1 = -1 << successive; /* -1 in the bit position being coded */
const prevpos = 0;
const decodeBaseline = (component: typeof components[0], pos: number) => {
while (bitsCount < 16) {
bitsData = (bitsData << 8) + (data[offset] | 0);
@ -770,19 +772,8 @@ export class f5stego {
if ((bitsData & 0xff) == 0xFF) offset++;
bitsCount += 8;
}
if (component.componentId == 1) {
// EMIT BITS HERE
component.blocks[pos + k] = (bitsData >>> (bitsCount - s)) & ((1 << s) - 1);
if (component.blocks[pos + k] < 1 << (s - 1)) component.blocks[pos + k] += (-1 << s) + 1;
if (this.gengen && component.blocks[pos + k] != 0) {
const v = (component.blocks[pos + k] < 0) ? 1 - (component.blocks[pos + k] & 1) : (component.blocks[pos + k] & 1);
const it = this.gengen.next(v);
if (it.done) {
throw it.value;
}
}
}
component.blocks[pos + k] = (bitsData >>> (bitsCount - s)) & ((1 << s) - 1);
if (component.blocks[pos + k] < 1 << (s - 1)) component.blocks[pos + k] += (-1 << s) + 1;
bitsCount -= s;
k++;
}
@ -972,6 +963,23 @@ export class f5stego {
let marker, mcuExpected, i, j, k, n, mcusPerLine, mcusPerRow, x, y;
let lastflushidx = 0;
const flushBits = () => {
const component = components.find(e => e.componentId == 1)!;
// EMIT BITS HERE
while (component.blocks[lastflushidx + 1] !== undefined) {
const blk = component.blocks[lastflushidx];
if (blk != 0) {
const v = (blk < 0) ? 1 - (blk & 1) : (blk & 1);
const it = this.gengen.next(v);
if (it.done) {
throw it.value;
}
}
lastflushidx++;
}
};
if (components.length == 1) {
mcusPerLine = components[0].blocksPerLine;
mcusPerRow = components[0].blocksPerColumn;
@ -1010,6 +1018,7 @@ export class f5stego {
}
}
flushBits();
}
} else {
mcusPerLine = frame.mcusPerLine;
@ -1052,6 +1061,7 @@ export class f5stego {
}
}
}
flushBits();
}
}
offset -= (bitsCount / 8) | 0;
@ -1129,8 +1139,8 @@ export class f5stego {
if (this.#frame.scanLines * this.#frame.samplesPerLine > this.maxPixels) throw "Image is too big.";
const componentsCount = data[offset++];
let componentId;
var componentsCount = data[offset++],
componentId;
let maxH = 0,
maxV = 0;
for (i = 0; i < componentsCount; i++) {
@ -1647,4 +1657,5 @@ export class f5stego {
return byteout.slice(0, outpos);
}
}

28
src/main.ts

@ -401,7 +401,7 @@ class CommandProcessor {
const convertToLocalEmbed = (wef: WorkerEmbeddedFile) => {
let ret: EmbeddedFileWithPreview;
ret = {...wef} as any;
ret = { ...wef } as any;
// handles bigger files where data is represented as a {url, header} object
if (typeof wef.data == "object") {
if ('url' in wef.data) {
@ -754,11 +754,15 @@ const startup = async (is4chanX = true) => {
if (!el && e.classList.contains('postContainer'))
el = [e];
if (el) {
appState.update(v => {
v.processing += el.length;
return v;
});
[...el].map(el => processPost(el as any));
for (const e of el) {
if (processed.has(e.id))
continue;
appState.update(v => {
v.processing += 1;
return v;
});
processPost(e as HTMLDivElement);
}
}
});
});
@ -916,12 +920,14 @@ document.addEventListener('ThreadUpdate', <any>(async (e: CustomEvent<any>) => {
const postContainer = document.getElementById("pc" + post.substring(post.indexOf(".") + 1)) as HTMLDivElement;
const fn = qp.getFilename(postContainer);
if (fn) {
appState.update(v => {
v.processing++;
return v;
});
if (!processed.has(postContainer.id)) {
appState.update(v => {
v.processing++;
return v;
});
processPost(postContainer);
processPost(postContainer);
}
}
}
}));

Loading…
Cancel
Save