Anti font encryption attempt

Keywords: Python encoding xml

Preface

Based on Baidu search information, blog article research, as well as the summary of questions.

Font encryption is garbled in the source code, but it is normal to display in the browser.

This post is for study only.

 

encryption

The general process of font encryption:

1. When the back-end returns data to the front-end, a unicode code is mapped with the encrypted characters and a font file is generated;

2. At this time, the data returned by the back end is the unicode mapped with the encrypted character. This unicode has no relationship with the encrypted character. It is converted to other characters according to the code table conversion;

3. The front end receives the data, analyzes the data according to the mapping of font file, and displays it to the interface.

This process is my guess and has not been practiced.

 

Decrypt

Take 58,

Characters to be decrypted: To be careful;

Decryption idea: according to browser parsing behavior

1. Find the font file

2. Find the real mapped character of the unicode code according to the unicode code of the character to be decrypted

Manual decryption

1. Find the font file of the characters to be decrypted, which can be found through css style;

58 font file is base64:

    

2. Transcode base64 and store it as a. ttf file:

Here( https://www.motobit.com/util/base64-decoder-encoder.asp )The website can decode the. bin file of base64 and store it as binary data, and change the. bin file suffix of the downloaded binary data to. ttf,

      

 

 

 

3. Open the font file through FontCreator software, and you can see the mapping relationship between characters and unicode:

      

 

 

    

4. Convert the characters to be decrypted to unicode: convert the characters to be decrypted to unicode: convert the characters to be decrypted to unicode; convert the characters to be decrypted to unicode; convert the characters to be decrypted to unicode; convert the characters to be decrypted to unicode; convert the characters to be decrypted to unicode to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted to be decrypted;

Via this website( https://www.css-js.com/tools/unicode.html )Online conversion, the results are as follows:

      

 

 

5. Find the corresponding characters in FontCreator software according to the Unicode of the characters to be decrypted (i.e. &

      

 

 

Code decryption

For example, python:

    

 1 from fontTools.ttLib import TTFont
 2 import base64
 3 
 4 
 5 
 6 # Module dependency:
 7     # base64 : Decode base64
 8     # TTFont : Resolve font file
 9 
10 
11 # Stored ttf File path and name
12 filePath = 'decode.ttf'
13 
14 # Font file's base64
15 base64str = 'AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzL4XQjtAAABjAAAAFZjbWFwq8J/ZQAAAhAAAAIuZ2x5ZuWIN0cAAARYAAADdGhlYWQYrcvJAAAA4AAAADZoaGVhCtADIwAAALwAAAAkaG10eC7qAAAAAAHkAAAALGxvY2ED7gSyAAAEQAAAABhtYXhwARgANgAAARgAAAAgbmFtZTd6VP8AAAfMAAACanBvc3QFRAYqAAAKOAAAAEUAAQAABmb+ZgAABLEAAAAABGgAAQAAAAAAAAAAAAAAAAAAAAsAAQAAAAEAAOGGAfhfDzz1AAsIAAAAAADak0BcAAAAANqTQFwAAP/mBGgGLgAAAAgAAgAAAAAAAAABAAAACwAqAAMAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAEERAGQAAUAAAUTBZkAAAEeBRMFmQAAA9cAZAIQAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAQJR2n6UGZv5mALgGZgGaAAAAAQAAAAAAAAAAAAAEsQAABLEAAASxAAAEsQAABLEAAASxAAAEsQAABLEAAASxAAAEsQAAAAAABQAAAAMAAAAsAAAABAAAAaYAAQAAAAAAoAADAAEAAAAsAAMACgAAAaYABAB0AAAAFAAQAAMABJR2lY+ZPJpLnjqeo59kn5Kfpf//AACUdpWPmTyaS546nqOfZJ+Sn6T//wAAAAAAAAAAAAAAAAAAAAAAAAABABQAFAAUABQAFAAUABQAFAAUAAAACQAEAAIAAwAKAAcACAAFAAEABgAAAQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAAiAAAAAAAAAAKAACUdgAAlHYAAAAJAACVjwAAlY8AAAAEAACZPAAAmTwAAAACAACaSwAAmksAAAADAACeOgAAnjoAAAAKAACeowAAnqMAAAAHAACfZAAAn2QAAAAIAACfkgAAn5IAAAAFAACfpAAAn6QAAAABAACfpQAAn6UAAAAGAAAAAAAAACgAPgBmAJoAvgDoASQBOAF+AboAAgAA/+YEWQYnAAoAEgAAExAAISAREAAjIgATECEgERAhIFsBEAECAez+6/rs/v3IATkBNP7S/sEC6AGaAaX85v54/mEBigGB/ZcCcwKJAAABAAAAAAQ1Bi4ACQAAKQE1IREFNSURIQQ1/IgBW/6cAicBWqkEmGe0oPp7AAEAAAAABCYGJwAXAAApATUBPgE1NCYjIgc1NjMyFhUUAgcBFSEEGPxSAcK6fpSMz7y389Hym9j+nwLGqgHButl0hI2wx43iv5D+69b+pwQAAQAA/+YEGQYnACEAABMWMzI2NRAhIzUzIBE0ISIHNTYzMhYVEAUVHgEVFAAjIiePn8igu/5bgXsBdf7jo5CYy8bw/sqow/7T+tyHAQN7nYQBJqIBFP9uuVjPpf7QVwQSyZbR/wBSAAACAAAAAARoBg0ACgASAAABIxEjESE1ATMRMyERNDcjBgcBBGjGvv0uAq3jxv58BAQOLf4zAZL+bgGSfwP8/CACiUVaJlH9TwABAAD/5gQhBg0AGAAANxYzMjYQJiMiBxEhFSERNjMyBBUUACEiJ7GcqaDEx71bmgL6/bxXLPUBEv7a/v3Zbu5mswEppA4DE63+SgX42uH+6kAAAAACAAD/5gRbBicAFgAiAAABJiMiAgMzNjMyEhUUACMiABEQACEyFwEUFjMyNjU0JiMiBgP6eYTJ9AIFbvHJ8P7r1+z+8wFhASClXv1Qo4eAoJeLhKQFRj7+ov7R1f762eP+3AFxAVMBmgHjLfwBmdq8lKCytAAAAAABAAAAAARNBg0ABgAACQEjASE1IQRN/aLLAkD8+gPvBcn6NwVgrQAAAwAA/+YESgYnABUAHwApAAABJDU0JDMyFhUQBRUEERQEIyIkNRAlATQmIyIGFRQXNgEEFRQWMzI2NTQBtv7rAQTKufD+3wFT/un6zf7+AUwBnIJvaJLz+P78/uGoh4OkAy+B9avXyqD+/osEev7aweXitAEohwF7aHh9YcJlZ/7qdNhwkI9r4QAAAAACAAD/5gRGBicAFwAjAAA3FjMyEhEGJwYjIgA1NAAzMgAREAAhIicTFBYzMjY1NCYjIga5gJTQ5QICZvHD/wABGN/nAQT+sP7Xo3FxoI16pqWHfaTSSgFIAS4CAsIBDNbkASX+lf6l/lP+MjUEHJy3p3en274AAAAAABAAxgABAAAAAAABAA8AAAABAAAAAAACAAcADwABAAAAAAADAA8AFgABAAAAAAAEAA8AJQABAAAAAAAFAAsANAABAAAAAAAGAA8APwABAAAAAAAKACsATgABAAAAAAALABMAeQADAAEECQABAB4AjAADAAEECQACAA4AqgADAAEECQADAB4AuAADAAEECQAEAB4A1gADAAEECQAFABYA9AADAAEECQAGAB4BCgADAAEECQAKAFYBKAADAAEECQALACYBfmZhbmdjaGFuLXNlY3JldFJlZ3VsYXJmYW5nY2hhbi1zZWNyZXRmYW5nY2hhbi1zZWNyZXRWZXJzaW9uIDEuMGZhbmdjaGFuLXNlY3JldEdlbmVyYXRlZCBieSBzdmcydHRmIGZyb20gRm9udGVsbG8gcHJvamVjdC5odHRwOi8vZm9udGVsbG8uY29tAGYAYQBuAGcAYwBoAGEAbgAtAHMAZQBjAHIAZQB0AFIAZQBnAHUAbABhAHIAZgBhAG4AZwBjAGgAYQBuAC0AcwBlAGMAcgBlAHQAZgBhAG4AZwBjAGgAYQBuAC0AcwBlAGMAcgBlAHQAVgBlAHIAcwBpAG8AbgAgADEALgAwAGYAYQBuAGcAYwBoAGEAbgAtAHMAZQBjAHIAZQB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAIAAAAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwECAQMBBAEFAQYBBwEIAQkBCgELAQwAAAAAAAAAAAAAAAAAAAAA'
16 
17 # Characters to be decrypted
18 encodestr = u'To be careful'
19 
20 
21 # Store files (in binary mode)
22 # filePath : Stored file path and name
23 # data : Data to be stored
24 def writeTTFFile(filePath, data):
25     #print(encodestr.encode("unicode_escape").decode())
26     #print(int(encodestr.encode("unicode_escape")[2:], 16))
27     with open(filePath, 'wb') as f:
28         f.write(data)
29 
30 # Parse fonts and decrypt characters to be decrypted
31 # filePath : Path and name of font file
32 # str : Characters to be decrypted
33 # return : Return decrypted characters
34 def TTFDecode(filePath, encodestr):
35     font = TTFont(filePath)
36     strRes = font.getBestCmap()
37     print(strRes)
38     glypDict = font.getReverseGlyphMap()
39     print(glypDict)
40     ret = ''
41     for ch in encodestr:  #Traverse the characters to be decrypted, decrypt one by one
42         strResKey = int(ch.encode("unicode_escape")[2:], 16)  #Convert a single character to unicode And intercept the hexadecimal part and convert it to a decimal digit
43         glypDictKey = strRes[strResKey]  #Through the conversion of the decimal digits in 'strRes' Find the corresponding glyph Resources
44         ret = ret + str(glypDict[glypDictKey] - 1)  #stay 'strRes' Found value in 'glypDict' Find out the corresponding characters and splice them to get the decrypted characters, Here minus 1 is the rule of 58 encryption, which may not be the case for other websites
45     return ret
46 
47 writeTTFFile(filePath, base64.b64decode(base64str))
48 decodestr = TTFDecode(filePath, encodestr)
49 print(decodestr)

 

The code focuses on lines 34 and 35, which analyze the mapping relationship of font files;

print(strRes) output is: {38006: 'glyph00009', 38287: 'glyph00004', 39228: 'glyph00002', 39499: 'glyph00003', 40506: 'glyph00010', 40611: 'glyph00007', 40804: 'glyph00008', 40850: 'glyph00005', 40868: 'glyph00001', 40869: 'glyph00006'}

      print(glypDict): {'glyph00000': 0, 'glyph00001': 1, 'glyph00002': 2, 'glyph00003': 3, 'glyph00004': 4, 'glyph00005': 5, 'glyph00006': 6, 'glyph00007': 7, 'glyph00008': 8, 'glyph00009': 9, 'glyph00010': 10}

For example: the character to be decrypted: the decimal of unicode encoding of_, so look up the corresponding value in strRes as glyph00003, glyph00003 look up the corresponding value in glyphict as 3, then subtract 1 to 2, and the decrypted character is 2

Minus 1 operation is the encryption rule of 58 website, which can be obtained through comparative observation.

    

ttf file can be converted into ttx file, which shows the mapping relationship intuitively. Through the code: TTFont('encode.ttf').saveXML('decode.ttx'), the transformation can be performed;

font.getBestCmap(): this code is the result of parsing

 

font.getReverseGlyphMap(): this code is the result of parsing:

 

 

 

 

Other demos

Characters to be decrypted: 𘢘𘢗𘢓𘢕;

Font file: http://qidian.gtimg.com/qd'anti'spider/punzuoms.woff

 1 def decode():
 2     encodestr = '𘢘𘢗𘢓𘢕'
 3     glypDict = {
 4         'zero': '0',
 5         'one': '1',
 6         'two': '2',
 7         'three': '3',
 8         'four': '4',
 9         'five': '5',
10         'six': '6',
11         'seven': '7',
12         'eight': '8',
13         'nine': '9',
14         'period': '.'
15 
16     }
17     strRes = TTFont(BytesIO(requests.get('http://qidian.gtimg.com/qd_anti_spider/PUNzUOms.woff').content)).getBestCmap()
18     print(strRes)
19     ret = ''
20     for ch in encodestr:
21         ret = ret + glypDict[strRes[int(ch.encode('unicode_escape')[2:], 16)]]
22     return ret
23 print(decode())

Different from 58, font file is. woff, but the principle is the same. When decrypting, you should decrypt it manually, cooperate with FontCreator software, or convert it to xml format, and observe carefully.

Posted by snidog on Sun, 15 Mar 2020 01:20:14 -0700