diff --git a/web/some_assembly_required_3/index.html b/web/some_assembly_required_3/index.html
new file mode 100644
index 0000000..6ec79d3
--- /dev/null
+++ b/web/some_assembly_required_3/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+ Enter flag:
+
+
+
+
+
diff --git a/web/some_assembly_required_3/index.js b/web/some_assembly_required_3/index.js
new file mode 100644
index 0000000..edd8a7f
--- /dev/null
+++ b/web/some_assembly_required_3/index.js
@@ -0,0 +1,195 @@
+const constants = [
+ 'exports',
+ '270328ewawLo',
+ 'instantiate',
+ '1OsuamQ',
+ 'Incorrect!',
+ 'length',
+ 'copy_char',
+ 'value',
+ '1512517ESezaM',
+ 'innerHTML',
+ 'check_flag',
+ 'result',
+ '1383842SQRPPf',
+ '924408cukzgO',
+ 'getElementById',
+ '418508cLDohp',
+ 'input',
+ 'Correct!',
+ '573XsMMHp',
+ 'arrayBuffer',
+ '183RUQBDE',
+ '38934oMACea',
+];
+
+const get_const = function(addr, _seemingly_unused) {
+ addr = addr - 0x11d;
+ let result = constants[addr];
+ return result;
+};
+
+// Stack aligner of some sort?
+(function() {
+ while (!![]) {
+ try {
+ const result =
+ -parseInt(get_const(0x122))
+ + -parseInt(get_const(0x12f))
+ + -parseInt(get_const(0x126)) * -parseInt(get_const(0x12b))
+ + -parseInt(get_const(0x132))
+ + parseInt(get_const(0x124))
+ + -parseInt(get_const(0x121)) * -parseInt(get_const(0x11f))
+ + parseInt(get_const(0x130));
+ if (result === 0x252604) break;
+ else constants['push'](constants['shift']());
+ } catch (e) {
+ constants['push'](constants['shift']());
+ }
+ }
+}());
+
+let exports;
+
+// Load the WebAssembly module and get its exports
+(async () => {
+ let checkFlagWasm = await fetch('./index.wasm'),
+ arrayBufferResult = await WebAssembly['instantiate'](await checkFlagWasm['arrayBuffer']()),
+ arrayBufferResultInstance = arrayBufferResult['instance'];
+ exports = arrayBufferResultInstance['exports'];
+})();
+
+function onButtonPress() {
+ let value = document['getElementById']('input')['value'];
+ const copy_char = exports['copy_char'];
+
+ for (let i = 0x0; i < value['length']; i++) {
+ const char_code = value['charCodeAt'](i);
+ copy_char(char_code, i);
+ }
+
+ exports['copy_char'](0x0, value['length']), exports['check_flag']() == 0x1
+ ? document['getElementById']('result')['innerHTML'] = 'Correct!'
+ : document['getElementById']('result')['innerHTML'] = 'Incorrect!';
+}
+
+// First attempt at reverse engineering copy_char/func3.
+// This is a relatively direct translation.
+
+function copy_char(var0, var1) {
+ const key = "\xf1\xa7\xf0\x07\xed";
+ // (global $global0 (mut i32) (i32.const 66864))
+ // (global $global1 i32 (i32.const 1072))
+ const var2 = exports['global0']['value'];
+ const var3 = 16;
+ const var4 = var2 - var3;
+ exports['memory']['buffer'][var4 + 12] = var0;
+ exports['memory']['buffer'][var4 + 8] = var1;
+ var5 = exports['memory']['buffer'][var4 + 12];
+ if (var5 !== 0) {
+ const var6 = 4;
+ const var7 = exports['memory']['buffer'][var4 + 8];
+ const var8 = 5;
+ const var9 = var7 % var8;
+ const var10 = var6 - var9;
+ const var11 = key.charCodeAt(var10);
+ const var12 = 24;
+ const var13 = var11 << var12;
+ const var14 = var13 >> var12;
+ const var15 = exports['memory']['buffer'][var4 + 12];
+ const var16 = var15 ^ var14;
+ exports['memory']['buffer'][var4 + 12] = var16;
+ }
+ const var17 = exports['memory']['buffer'][var4 + 12];
+ const var18 = exports['memory']['buffer'][var4 + 8];
+ exports['memory']['buffer'][var18 + 1072] = var17;
+}
+
+// Let's shorten it more and get rid of all the memory shuffling
+
+function copy_char(c, i) {
+ const key = "\xf1\xa7\xf0\x07\xed";
+ if (c !== 0) {
+ const key_index = (4 - (i % 5));
+ const key_char = key.charCodeAt(key_index);
+ c ^= key_char;
+ }
+ exports['memory']['buffer'][i + 1072] = c;
+}
+
+
+// copy_char
+// (func $func3 (param $var0 i32) (param $var1 i32)
+// (local $var2 i32) (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32) (local $var11 i32) (local $var12 i32) (local $var13 i32) (local $var14 i32) (local $var15 i32) (local $var16 i32) (local $var17 i32) (local $var18 i32)
+// global.get $global0
+// local.set $var2
+// i32.const 16
+// local.set $var3
+// local.get $var2
+// local.get $var3
+// i32.sub
+// local.set $var4
+// local.get $var4
+// local.get $var0
+// i32.store offset=12
+// local.get $var4
+// local.get $var1
+// i32.store offset=8
+// local.get $var4
+// i32.load offset=12
+// local.set $var5
+// block $label0
+// local.get $var5
+// i32.eqz
+// br_if $label0
+// i32.const 4
+// local.set $var6
+// local.get $var4
+// i32.load offset=8
+// local.set $var7
+// i32.const 5
+// local.set $var8
+// local.get $var7
+// local.get $var8
+// i32.rem_s
+// local.set $var9
+// local.get $var6
+// local.get $var9
+// i32.sub
+// local.set $var10
+// local.get $var10
+// i32.load8_u offset=1067
+// local.set $var11
+// i32.const 24
+// local.set $var12
+// local.get $var11
+// local.get $var12
+// i32.shl
+// local.set $var13
+// local.get $var13
+// local.get $var12
+// i32.shr_s
+// local.set $var14
+// local.get $var4
+// i32.load offset=12
+// local.set $var15
+// local.get $var15
+// local.get $var14
+// i32.xor
+// local.set $var16
+// local.get $var4
+// local.get $var16
+// i32.store offset=12
+// end $label0
+// local.get $var4
+// i32.load offset=12
+// local.set $var17
+// local.get $var4
+// i32.load offset=8
+// local.set $var18
+// local.get $var18
+// local.get $var17
+// i32.store8 offset=1072
+// return
+// )
+// (data (i32.const 1024) "\9dn\93\c8\b2\b9A\8b\94\90\dd>\94\97\90\dd?\c4\c2\c9\dd4\c2\c5\97\db1\93\92\c0\da6\93\93\c1\d9>\91\c1\97\90\00\00")
diff --git a/web/some_assembly_required_3/index.wasm b/web/some_assembly_required_3/index.wasm
new file mode 100644
index 0000000..8cc55fe
Binary files /dev/null and b/web/some_assembly_required_3/index.wasm differ
diff --git a/web/some_assembly_required_3/index.wat b/web/some_assembly_required_3/index.wat
new file mode 100644
index 0000000..96234db
--- /dev/null
+++ b/web/some_assembly_required_3/index.wat
@@ -0,0 +1,310 @@
+(module
+ (table $table0 1 1 funcref)
+ (memory $memory0 2)
+ (global $global0 (mut i32) (i32.const 66864))
+ (global $global1 i32 (i32.const 1072))
+ (global $global2 i32 (i32.const 1067))
+ (global $global3 i32 (i32.const 1024))
+ (global $global4 i32 (i32.const 1328))
+ (global $global5 i32 (i32.const 1024))
+ (global $global6 i32 (i32.const 66864))
+ (global $global7 i32 (i32.const 0))
+ (global $global8 i32 (i32.const 1))
+ (export "memory" (memory $memory0))
+ (export "__wasm_call_ctors" (func $func0))
+ (export "strcmp" (func $func1))
+ (export "check_flag" (func $func2))
+ (export "input" (global $global1))
+ (export "copy_char" (func $func3))
+ (export "key" (global $global2))
+ (export "__dso_handle" (global $global3))
+ (export "__data_end" (global $global4))
+ (export "__global_base" (global $global5))
+ (export "__heap_base" (global $global6))
+ (export "__memory_base" (global $global7))
+ (export "__table_base" (global $global8))
+ (func $func0
+ )
+ (func $func1 (param $var0 i32) (param $var1 i32) (result i32)
+ (local $var2 i32) (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32) (local $var11 i32) (local $var12 i32) (local $var13 i32) (local $var14 i32) (local $var15 i32) (local $var16 i32) (local $var17 i32) (local $var18 i32) (local $var19 i32) (local $var20 i32) (local $var21 i32) (local $var22 i32) (local $var23 i32) (local $var24 i32) (local $var25 i32) (local $var26 i32) (local $var27 i32) (local $var28 i32) (local $var29 i32) (local $var30 i32) (local $var31 i32) (local $var32 i32) (local $var33 i32) (local $var34 i32) (local $var35 i32) (local $var36 i32) (local $var37 i32) (local $var38 i32) (local $var39 i32) (local $var40 i32) (local $var41 i32) (local $var42 i32) (local $var43 i32)
+ global.get $global0
+ local.set $var2
+ i32.const 32
+ local.set $var3
+ local.get $var2
+ local.get $var3
+ i32.sub
+ local.set $var4
+ local.get $var4
+ local.get $var0
+ i32.store offset=24
+ local.get $var4
+ local.get $var1
+ i32.store offset=20
+ local.get $var4
+ i32.load offset=24
+ local.set $var5
+ local.get $var4
+ local.get $var5
+ i32.store offset=16
+ local.get $var4
+ i32.load offset=20
+ local.set $var6
+ local.get $var4
+ local.get $var6
+ i32.store offset=12
+ block $label1
+ loop $label2
+ local.get $var4
+ i32.load offset=16
+ local.set $var7
+ i32.const 1
+ local.set $var8
+ local.get $var7
+ local.get $var8
+ i32.add
+ local.set $var9
+ local.get $var4
+ local.get $var9
+ i32.store offset=16
+ local.get $var7
+ i32.load8_u
+ local.set $var10
+ local.get $var4
+ local.get $var10
+ i32.store8 offset=11
+ local.get $var4
+ i32.load offset=12
+ local.set $var11
+ i32.const 1
+ local.set $var12
+ local.get $var11
+ local.get $var12
+ i32.add
+ local.set $var13
+ local.get $var4
+ local.get $var13
+ i32.store offset=12
+ local.get $var11
+ i32.load8_u
+ local.set $var14
+ local.get $var4
+ local.get $var14
+ i32.store8 offset=10
+ local.get $var4
+ i32.load8_u offset=11
+ local.set $var15
+ i32.const 255
+ local.set $var16
+ local.get $var15
+ local.get $var16
+ i32.and
+ local.set $var17
+ block $label0
+ local.get $var17
+ br_if $label0
+ local.get $var4
+ i32.load8_u offset=11
+ local.set $var18
+ i32.const 255
+ local.set $var19
+ local.get $var18
+ local.get $var19
+ i32.and
+ local.set $var20
+ local.get $var4
+ i32.load8_u offset=10
+ local.set $var21
+ i32.const 255
+ local.set $var22
+ local.get $var21
+ local.get $var22
+ i32.and
+ local.set $var23
+ local.get $var20
+ local.get $var23
+ i32.sub
+ local.set $var24
+ local.get $var4
+ local.get $var24
+ i32.store offset=28
+ br $label1
+ end $label0
+ local.get $var4
+ i32.load8_u offset=11
+ local.set $var25
+ i32.const 255
+ local.set $var26
+ local.get $var25
+ local.get $var26
+ i32.and
+ local.set $var27
+ local.get $var4
+ i32.load8_u offset=10
+ local.set $var28
+ i32.const 255
+ local.set $var29
+ local.get $var28
+ local.get $var29
+ i32.and
+ local.set $var30
+ local.get $var27
+ local.set $var31
+ local.get $var30
+ local.set $var32
+ local.get $var31
+ local.get $var32
+ i32.eq
+ local.set $var33
+ i32.const 1
+ local.set $var34
+ local.get $var33
+ local.get $var34
+ i32.and
+ local.set $var35
+ local.get $var35
+ br_if $label2
+ end $label2
+ local.get $var4
+ i32.load8_u offset=11
+ local.set $var36
+ i32.const 255
+ local.set $var37
+ local.get $var36
+ local.get $var37
+ i32.and
+ local.set $var38
+ local.get $var4
+ i32.load8_u offset=10
+ local.set $var39
+ i32.const 255
+ local.set $var40
+ local.get $var39
+ local.get $var40
+ i32.and
+ local.set $var41
+ local.get $var38
+ local.get $var41
+ i32.sub
+ local.set $var42
+ local.get $var4
+ local.get $var42
+ i32.store offset=28
+ end $label1
+ local.get $var4
+ i32.load offset=28
+ local.set $var43
+ local.get $var43
+ return
+ )
+ (func $func2 (result i32)
+ (local $var0 i32) (local $var1 i32) (local $var2 i32) (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32)
+ i32.const 0
+ local.set $var0
+ i32.const 1072
+ local.set $var1
+ i32.const 1024
+ local.set $var2
+ local.get $var2
+ local.get $var1
+ call $func1
+ local.set $var3
+ local.get $var3
+ local.set $var4
+ local.get $var0
+ local.set $var5
+ local.get $var4
+ local.get $var5
+ i32.ne
+ local.set $var6
+ i32.const -1
+ local.set $var7
+ local.get $var6
+ local.get $var7
+ i32.xor
+ local.set $var8
+ i32.const 1
+ local.set $var9
+ local.get $var8
+ local.get $var9
+ i32.and
+ local.set $var10
+ local.get $var10
+ return
+ )
+ (func $func3 (param $var0 i32) (param $var1 i32)
+ (local $var2 i32) (local $var3 i32) (local $var4 i32) (local $var5 i32) (local $var6 i32) (local $var7 i32) (local $var8 i32) (local $var9 i32) (local $var10 i32) (local $var11 i32) (local $var12 i32) (local $var13 i32) (local $var14 i32) (local $var15 i32) (local $var16 i32) (local $var17 i32) (local $var18 i32)
+ global.get $global0
+ local.set $var2
+ i32.const 16
+ local.set $var3
+ local.get $var2
+ local.get $var3
+ i32.sub
+ local.set $var4
+ local.get $var4
+ local.get $var0
+ i32.store offset=12
+ local.get $var4
+ local.get $var1
+ i32.store offset=8
+ local.get $var4
+ i32.load offset=12
+ local.set $var5
+ block $label0
+ local.get $var5
+ i32.eqz
+ br_if $label0
+ i32.const 4
+ local.set $var6
+ local.get $var4
+ i32.load offset=8
+ local.set $var7
+ i32.const 5
+ local.set $var8
+ local.get $var7
+ local.get $var8
+ i32.rem_s
+ local.set $var9
+ local.get $var6
+ local.get $var9
+ i32.sub
+ local.set $var10
+ local.get $var10
+ i32.load8_u offset=1067
+ local.set $var11
+ i32.const 24
+ local.set $var12
+ local.get $var11
+ local.get $var12
+ i32.shl
+ local.set $var13
+ local.get $var13
+ local.get $var12
+ i32.shr_s
+ local.set $var14
+ local.get $var4
+ i32.load offset=12
+ local.set $var15
+ local.get $var15
+ local.get $var14
+ i32.xor
+ local.set $var16
+ local.get $var4
+ local.get $var16
+ i32.store offset=12
+ end $label0
+ local.get $var4
+ i32.load offset=12
+ local.set $var17
+ local.get $var4
+ i32.load offset=8
+ local.set $var18
+ local.get $var18
+ local.get $var17
+ i32.store8 offset=1072
+ return
+ )
+ (data (i32.const 1024) "\9dn\93\c8\b2\b9A\8b\94\90\dd>\94\97\90\dd?\c4\c2\c9\dd4\c2\c5\97\db1\93\92\c0\da6\93\93\c1\d9>\91\c1\97\90\00\00")
+ (data (i32.const 1067) "\f1\a7\f0\07\ed")
+)
diff --git a/web/some_assembly_required_3/solve.py b/web/some_assembly_required_3/solve.py
new file mode 100755
index 0000000..378411f
--- /dev/null
+++ b/web/some_assembly_required_3/solve.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+output = b"\x9dn\x93\xc8\xb2\xb9A\x8b\x94\x90\xdd>\x94\x97\x90\xdd?\xc4\xc2\xc9\xdd4\xc2\xc5\x97\xdb1\x93\x92\xc0\xda6\x93\x93\xc1\xd9>\x91\xc1\x97\x90\x00\x00"
+key = b"\xf1\xa7\xf0\x07\xed"
+
+def copy_char_inv(c: int, i: int) -> int:
+ if c != 0:
+ key_index = (4 - (i % 5))
+ key_char = key[key_index]
+ c ^= key_char
+ return c
+
+def main():
+ for i, c in enumerate(output):
+ b = copy_char_inv(c, i)
+ print(chr(b), end="")
+ print()
+
+if __name__ == "__main__":
+ main()