Skip to content
This repository was archived by the owner on Mar 26, 2019. It is now read-only.

Commit 0d0a6bc

Browse files
authored
Add files via upload
1 parent 8665cbe commit 0d0a6bc

29 files changed

+7382
-0
lines changed

obf/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# ithare::obf
2+
C++ Code+Data Obfuscation Library with Build-Time Polymorphism
3+
4+
**Primary Target Audience**: Primarily, the library is intended for **multiplayer game developers concerned about bots**. Use of the library to protect programs from piracy, while potentially possible (especially if speaking about the programs with online protection), is not among the goals (and while it might improve things, IMO anti-piracy fight will be still next-to-hopeless; in contrast - anti-bot fight DOES have a fighting chance). **ithare::obf aims to withstand the-best-available reverse-engineering tools such as IDA Pro's decompiler** (see also [first results](#first-results) below).
5+
6+
**Secondary Target Audience**: C++ compiler writers (and those willing to learn new ways to abuse the compiler <wink />). Apparently, ithare::obf tends to generate LOTS of ugly code (and can generate even-uglier-code if desired <wink />); as such, it puts optimizer under significant stress (with almost no efforts to generate testing code, as generated code is supposed to be functionally-equivalent to the original one). In particular, even without aiming to test the compiler, I already ran into a code-generation bug with one of the intrinsics, and one case of compile-in-Release-mode taking atrociously long times (plus who-knows-how-many INTERNAL COMPILER ERRORs induced by my own mistakes).
7+
8+
**The Big Idea**: Automatically generated obfuscation code+data code while leaving the source (mostly) readable, with obfuscation only *declared* in the source. Obfuscation code is heavily randomized depending on ITHARE_OBF_SEED macro, so changing it causes a major reshuffling even if the source code is 100% the same.
9+
10+
 
11+
12+
**Rationale**: See http://ithare.com/bot-fighting-201-declarative-datacode-obfuscation-with-build-time-polymorphism-in-c/ and http://ithare.com/bot-fighting-201-part-2-obfuscating-literals/
13+
14+
**Implementation**: IMO - it is a rather interesting exercise in C++-provided code generation. We have a template class obf_injection<>, with OBFCYCLES (meaning "CPU cycles we're allowed to burn") being one of the parameters, and OBFSEED being another one; obf_injection<> randomly chooses which of obf_injection_version<>'s to use - and obf_injection_version<> does some version-specific obfuscation stuff, and instantiates another obf_injection<> but with less CYCLES left. This template recursion goes on until CYCLES goes to zero. That's pretty much it, the rest is about some basic maths and some basic template+constexpr C++17 programming.
15+
* NB: while formally, it is probably possible to implement the same thing under C++11 (and maybe even with C++03) - without proper support for constexprs I wouldn't be able to write it, so **C++17 is THE MUST** (="I am not going to support anything lower than that").
16+
17+
<a name="first-results"></a>
18+
**First Results**: http://ithare.com/bot-fighting-201-part-3-ithareobf-an-open-source-datasource-randomized-obfuscation-library
19+
20+
&nbsp;
21+
22+
**Requirements**: v0.01 - Visual Studio 2017 with /std:c++latest (and /cgthreads1 recommended as a workaround for a suspected bug in MSVC linker); for v0.02 support for Clang (with -std=c++1z) is being added
23+
24+
**Status**: v0.01 is PRE-ALPHA (actually - more like proof of concept). No known bugs, but testing was very limited, and probably there are still MANY issues (mostly with refusing to compile).
25+
26+
**Current Work**: v0.02 - a LOT of structural improvements coming (currently being developed in [develop branch](https://github.com/ITHare/obf/tree/develop), though still WIP and may occasionally ), hopefully to become a viable "alpha". LOTS of improvements, such as added support for operations without complete restore of the value (proof of concept DONE, to be extended), support for real injections (not just bijections) - DONE, support for Clang/Mac (DONE), automated randomized testing (1st version DONE), a way to debug compile-time failures (TODO), significantly improved PRNGs (with an option to use 128-bit keys and real compile-time encryption) - DONE, support for different variations of the same injection (DONE), "official" way to add your own injections (TODO), and probably something-else-I-forgot-about.
27+
28+
**How to Help**: Until v0.02 is out - there isn't much to delegate, but **if you're interested in the library - PLEASE leave a comment** on http://ithare.com/bot-fighting-201-part-3-ithareobf-an-open-source-datasource-randomized-obfuscation-library encouraging me to work on ithare::obf harder (I am serious, there is no point in doing things if there is little interest in using them). After v0.02 is out, ideas and implementations of new injections and various generated trickery would be possible (and certainly VERY welcome; the whole point of this project is in having LOTS of different blocks-to-build-randomized-code-from).

obf/no-longer-standard/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This folder is intended to store "obfuscated adaptations" of certain 3rd-party libraries.
2+
3+
As a big fat rule of thumb, "obfuscated adaptations" will inherit the license of the original library-being-adapted.
4+
5+
In addition to providing an "obfuscated option", they're also likely to include constexpr-friendly versions of the relevant functions (such as constexpr-friendly cryptography, as well as whitebox-cryptography, in tls/ subproject).
6+

obf/no-longer-standard/tls/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This is an "obfuscated TLS" library.
2+
3+
Even when it is completed, it is going to be an ABSOLUTELY MINIMAL version, (supporting ONLY TLS1.2, with ONLY ONE cipher, etc. etc.).
4+
5+
It is currently derived from OpenSSL v1.1.0g. As a result - this project is licensed under "OpenSSL license".
6+
7+
Also, as OpenSSL license prohibits use of "OpenSSL" in the name of the derived projects - this project is named "Obfuscated TLS".
+337
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
/*
2+
* Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the OpenSSL license (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
10+
//OBF: Adapted from OpenSSL 1.1.0g, file internal/chacha.h:
11+
12+
/*
13+
* ChaCha20_ctr32 encrypts |len| bytes from |inp| with the given key and
14+
* nonce and writes the result to |out|, which may be equal to |inp|.
15+
* The |key| is not 32 bytes of verbatim key material though, but the
16+
* said material collected into 8 32-bit elements array in host byte
17+
* order. Same approach applies to nonce: the |counter| argument is
18+
* pointer to concatenated nonce and counter values collected into 4
19+
* 32-bit elements. This, passing crypto material collected into 32-bit
20+
* elements as opposite to passing verbatim byte vectors, is chosen for
21+
* efficiency in multi-call scenarios.
22+
*/
23+
24+
/*
25+
* You can notice that there is no key setup procedure. Because it's
26+
* as trivial as collecting bytes into 32-bit elements, it's reckoned
27+
* that below macro is sufficient.
28+
*/
29+
30+
//OBF: Adapted from OpenSSL 1.1.0g, file chacha_enc.c
31+
// As we're moving all the stuff to headers, to avoid potential for name collisions we have to:
32+
// Move whatever-possible to namespace ithare::obf::tls::
33+
// Add prefix ITHARE_OBF_TLS_ to all the macros (as macros don't belong to any namespace)
34+
35+
#ifndef ithare_obf_tls_crypto_chacha_h_included
36+
#define ithare_obf_tls_crypto_chacha_h_included
37+
38+
#include "../../../src/obf.h"
39+
#include "../../../src/obf_lib.h"
40+
41+
namespace ithare {
42+
namespace obf {
43+
namespace tls {
44+
45+
constexpr int CHACHA_KEY_SIZE = 32;
46+
constexpr int CHACHA_CTR_SIZE = 16;
47+
constexpr int CHACHA_BLK_SIZE = 64;
48+
49+
#define ITHARE_OBF_TLS_CHACHA_U8TOU32(p) ( \
50+
((unsigned int)(p)[0]) | ((unsigned int)(p)[1]<<8) | \
51+
((unsigned int)(p)[2]<<16) | ((unsigned int)(p)[3]<<24) )
52+
53+
/* Adapted from the public domain code by D. Bernstein from SUPERCOP. */
54+
55+
union chacha_buf {
56+
uint32_t u[16];
57+
uint8_t c[64];//CANNOT be used in constexpr calls; use get_byte_n() below instead in constexpr
58+
59+
constexpr uint8_t get_byte_n( size_t idx) const {
60+
assert(idx <= 63);
61+
size_t uidx = idx / 4;
62+
size_t intraidx = idx % 4;
63+
return uint8_t(u[uidx] >> (8*intraidx));
64+
}
65+
};
66+
static_assert(sizeof(chacha_buf)==64);
67+
68+
# define ITHARE_OBF_TLS_ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n))))
69+
70+
# define ITHARE_OBF_TLS_U32TO8_LITTLE(p, v) do { \
71+
(p)[0] = (uint8_t)(v >> 0); \
72+
(p)[1] = (uint8_t)(v >> 8); \
73+
(p)[2] = (uint8_t)(v >> 16); \
74+
(p)[3] = (uint8_t)(v >> 24); \
75+
} while(0)
76+
77+
/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */
78+
# define ITHARE_OBF_TLS_QUARTERROUND(a,b,c,d) ( \
79+
x[a] += x[b], x[d] = ITHARE_OBF_TLS_ROTATE((x[d] ^ x[a]),16), \
80+
x[c] += x[d], x[b] = ITHARE_OBF_TLS_ROTATE((x[b] ^ x[c]),12), \
81+
x[a] += x[b], x[d] = ITHARE_OBF_TLS_ROTATE((x[d] ^ x[a]), 8), \
82+
x[c] += x[d], x[b] = ITHARE_OBF_TLS_ROTATE((x[b] ^ x[c]), 7) )
83+
84+
/* chacha_core performs 20 rounds of ChaCha on the input words in
85+
* |input| and writes the 64 output bytes to |output|. */
86+
ITHARE_OBF_DECLARELIBFUNC
87+
void chacha20_core(chacha_buf *output, const uint32_t input[16])
88+
{
89+
ITHARE_OBF_DBGPRINTLIBFUNCNAMEX("chacha_core");
90+
ITHARE_OBFLIBM1(uint32_t) x[16] = {}; ITHARE_OBF_DBGPRINTLIBX(x[0]);
91+
ITHARE_OBF_CALLFROMLIB(obf_copyarray)(x,input);
92+
93+
for (int i = 20; i > 0; i -= 2) {
94+
ITHARE_OBF_TLS_QUARTERROUND(0, 4, 8, 12);
95+
ITHARE_OBF_TLS_QUARTERROUND(1, 5, 9, 13);
96+
ITHARE_OBF_TLS_QUARTERROUND(2, 6, 10, 14);
97+
ITHARE_OBF_TLS_QUARTERROUND(3, 7, 11, 15);
98+
ITHARE_OBF_TLS_QUARTERROUND(0, 5, 10, 15);
99+
ITHARE_OBF_TLS_QUARTERROUND(1, 6, 11, 12);
100+
ITHARE_OBF_TLS_QUARTERROUND(2, 7, 8, 13);
101+
ITHARE_OBF_TLS_QUARTERROUND(3, 4, 9, 14);
102+
}
103+
104+
static_assert(obf_endian::native == obf_endian::little);
105+
if constexpr (obf_endian::native == obf_endian::little) {
106+
for (int i = 0; i < 16; ++i)
107+
output->u[i] = x[i] + input[i];
108+
}
109+
/* else ++big-endian: test
110+
for (int i = 0; i < 16; ++i)
111+
ITHARE_OBF_TLS_U32TO8_LITTLE(output->c + 4 * i, (x[i] + input[i]));
112+
}*/
113+
}
114+
115+
ITHARE_OBF_DECLARELIBFUNC
116+
void ChaCha20_ctr32(unsigned char *out, const unsigned char *inp,
117+
size_t len, const unsigned int key[8],
118+
const unsigned int counter[4])
119+
{
120+
uint32_t input[16] = {};//TODO: move initialization here
121+
122+
/* sigma constant "expand 32-byte k" in little-endian encoding */
123+
input[0] = ((uint32_t)'e') | ((uint32_t)'x'<<8) | ((uint32_t)'p'<<16) | ((uint32_t)'a'<<24);
124+
input[1] = ((uint32_t)'n') | ((uint32_t)'d'<<8) | ((uint32_t)' '<<16) | ((uint32_t)'3'<<24);
125+
input[2] = ((uint32_t)'2') | ((uint32_t)'-'<<8) | ((uint32_t)'b'<<16) | ((uint32_t)'y'<<24);
126+
input[3] = ((uint32_t)'t') | ((uint32_t)'e'<<8) | ((uint32_t)' '<<16) | ((uint32_t)'k'<<24);
127+
128+
input[4] = key[0];
129+
input[5] = key[1];
130+
input[6] = key[2];
131+
input[7] = key[3];
132+
input[8] = key[4];
133+
input[9] = key[5];
134+
input[10] = key[6];
135+
input[11] = key[7];
136+
137+
input[12] = counter[0];
138+
input[13] = counter[1];
139+
input[14] = counter[2];
140+
input[15] = counter[3];
141+
142+
chacha_buf buf = {};
143+
while (len > 0) {
144+
size_t todo = sizeof(buf);
145+
if (len < todo)
146+
todo = len;
147+
148+
ITHARE_OBF_CALLFROMLIB(chacha20_core)(&buf, input);
149+
150+
for (size_t i = 0; i < todo; i++) {
151+
if constexpr(obfflags&obf_flag_is_constexpr)//potential big-endian issues?
152+
out[i] = inp[i] ^ buf.get_byte_n(i);
153+
else
154+
out[i] = inp[i] ^ buf.c[i];
155+
}
156+
out += todo;
157+
inp += todo;
158+
len -= todo;
159+
160+
/*
161+
* Advance 32-bit counter. Note that as subroutine is so to
162+
* say nonce-agnostic, this limited counter width doesn't
163+
* prevent caller from implementing wider counter. It would
164+
* simply take two calls split on counter overflow...
165+
*/
166+
input[12]++;
167+
}
168+
}
169+
170+
//OBF: Adapted from OpenSSL 1.1.0g, CHACHA part of file crypto/evp/e_chacha20_poly1305.c
171+
//OBF: combined stuff into EVP_CHACHA class
172+
173+
class EVP_CHACHA {
174+
struct KEY {//former EVP_CHACHA_KEY
175+
struct {
176+
alignas(double) /* this ensures even sizeof(EVP_CHACHA_KEY)%8==0 */
177+
unsigned int d[CHACHA_KEY_SIZE / 4];
178+
} key;
179+
unsigned int counter[CHACHA_CTR_SIZE / 4];
180+
unsigned char buf[CHACHA_BLK_SIZE];
181+
unsigned int partial_len;
182+
};
183+
KEY key;
184+
185+
constexpr EVP_CHACHA( obf_private_constructor_tag, const KEY&& key_ )
186+
: key(std::move(key_)) {
187+
}
188+
ITHARE_OBF_DECLARELIBFUNC
189+
static KEY init_key(const unsigned char user_key[CHACHA_KEY_SIZE],
190+
const unsigned char iv[CHACHA_CTR_SIZE], int enc){
191+
KEY key = {};
192+
193+
if (user_key)
194+
for (unsigned int i = 0; i < CHACHA_KEY_SIZE; i+=4) {
195+
key.key.d[i/4] = ITHARE_OBF_TLS_CHACHA_U8TOU32(user_key+i);
196+
}
197+
198+
if (iv)
199+
for (unsigned int i = 0; i < CHACHA_CTR_SIZE; i+=4) {
200+
key.counter[i/4] = ITHARE_OBF_TLS_CHACHA_U8TOU32(iv+i);
201+
}
202+
203+
key.partial_len = 0;
204+
return key;
205+
}
206+
ITHARE_OBF_DECLARELIBFUNC
207+
static void cipher( KEY& key, unsigned char *out,
208+
const unsigned char *inp, size_t len)
209+
{
210+
ITHARE_OBF_DBGPRINTLIBFUNCNAMEX("EVP_CHACHA::cipher");
211+
ITHARE_OBFLIB(unsigned int) n = key.partial_len; ITHARE_OBF_DBGPRINTLIBX(n);
212+
if (n) {
213+
while (len && n < ITHARE_OBFILIB(CHACHA_BLK_SIZE)) {
214+
*out++ = *inp++ ^ key.buf[n++];
215+
len--;
216+
}
217+
key.partial_len = n;
218+
219+
if (len == 0)
220+
return;
221+
222+
if (n == CHACHA_BLK_SIZE) {
223+
key.partial_len = 0;
224+
key.counter[0]++;
225+
if (key.counter[0] == 0)
226+
key.counter[1]++;
227+
}
228+
}
229+
230+
unsigned int rem = (unsigned int)(len % CHACHA_BLK_SIZE);
231+
len -= rem;
232+
unsigned int ctr32 = key.counter[0];//TODO: is it really unsigned int, or maybe uint32_t?
233+
while (len >= CHACHA_BLK_SIZE) {
234+
size_t blocks = len / CHACHA_BLK_SIZE;
235+
/*
236+
* 1<<28 is just a not-so-small yet not-so-large number...
237+
* Below condition is practically never met, but it has to
238+
* be checked for code correctness.
239+
*/
240+
if (sizeof(size_t)>sizeof(unsigned int) && blocks>(1U<<28))
241+
blocks = (1U<<28);
242+
243+
/*
244+
* As ChaCha20_ctr32 operates on 32-bit counter, caller
245+
* has to handle overflow. 'if' below detects the
246+
* overflow, which is then handled by limiting the
247+
* amount of blocks to the exact overflow point...
248+
*/
249+
ctr32 += (unsigned int)blocks;
250+
if (ctr32 < blocks) {
251+
blocks -= ctr32;
252+
ctr32 = 0;
253+
}
254+
blocks *= CHACHA_BLK_SIZE;
255+
ITHARE_OBF_CALLFROMLIB(ChaCha20_ctr32)(out, inp, blocks, key.key.d, key.counter);
256+
len -= blocks;
257+
inp += blocks;
258+
out += blocks;
259+
260+
key.counter[0] = ctr32;
261+
if (ctr32 == 0) key.counter[1]++;
262+
}
263+
264+
if (rem) {
265+
ITHARE_OBF_CALLFROMLIB(obf_zeroarray)(key.buf);
266+
ITHARE_OBF_CALLFROMLIB(ChaCha20_ctr32)(key.buf, key.buf, CHACHA_BLK_SIZE,
267+
key.key.d, key.counter);
268+
for (n = 0; n < rem; n++)
269+
out[n] = inp[n] ^ key.buf[n];
270+
key.partial_len = rem;
271+
}
272+
}
273+
274+
public:
275+
ITHARE_OBF_DECLARELIBFUNC //cannot really invoke constructors with explicit template parameters :-(
276+
// use EVP_CHACHA::construct<...> defined below instead
277+
EVP_CHACHA( const unsigned char user_key[CHACHA_KEY_SIZE],
278+
const unsigned char iv[CHACHA_CTR_SIZE], int enc)
279+
: key(init_key(user_key,iv,enc)) {
280+
}
281+
ITHARE_OBF_DECLARELIBFUNC
282+
static EVP_CHACHA construct(const unsigned char user_key[CHACHA_KEY_SIZE],
283+
const unsigned char iv[CHACHA_CTR_SIZE], int enc){
284+
return EVP_CHACHA(obf_private_constructor_tag(),std::move(init_key(user_key,iv,enc)));
285+
}
286+
287+
ITHARE_OBF_DECLARELIBFUNC
288+
void cipher(unsigned char *out,
289+
const unsigned char *inp, size_t len) {
290+
ITHARE_OBF_CALLFROMLIB(cipher)(key, out, inp, len);
291+
}
292+
293+
ITHARE_OBF_DECLARELIBFUNC_WITHEXTRA(size_t N)
294+
std::pair<EVP_CHACHA,ObfArrayWrapper<unsigned char,N> > constexpr_cipher(const unsigned char (&inp)[N]) const {
295+
KEY modifiable_key = key;
296+
ObfArrayWrapper<unsigned char,N> out = {};
297+
ITHARE_OBF_CALL_AS_CONSTEXPR(cipher)(modifiable_key,out.arr,inp,N);
298+
EVP_CHACHA new_state = EVP_CHACHA(obf_private_constructor_tag(),std::move(modifiable_key));
299+
return std::pair<EVP_CHACHA,ObfArrayWrapper<unsigned char,N>>(new_state,out);
300+
}
301+
};
302+
303+
304+
305+
#if 0
306+
static const EVP_CIPHER chacha20 = {
307+
NID_chacha20,
308+
1, /* block_size */
309+
CHACHA_KEY_SIZE, /* key_len */
310+
CHACHA_CTR_SIZE, /* iv_len, 128-bit counter in the context */
311+
EVP_CIPH_CUSTOM_IV | EVP_CIPH_ALWAYS_CALL_INIT,
312+
chacha_init_key,
313+
chacha_cipher,
314+
NULL,
315+
sizeof(EVP_CHACHA_KEY),
316+
NULL,
317+
NULL,
318+
NULL,
319+
NULL
320+
};
321+
322+
const EVP_CIPHER *EVP_chacha20(void)
323+
{
324+
return (&chacha20);
325+
}
326+
#endif
327+
328+
#undef ITHARE_OBF_TLS_QUARTERROUND
329+
#undef ITHARE_OBF_TLS_U32TO8_LITTLE
330+
#undef ITHARE_OBF_TLS_ROTATE
331+
#undef ITHARE_OBF_TLS_CHACHA_U8TOU32
332+
333+
}//namespace tls
334+
}//namespace obf
335+
}//namespace ithare
336+
337+
#endif //#ifndef ithare_obf_tls_crypto_chacha_h_included

0 commit comments

Comments
 (0)