Table of contents
1. Case Analysis
- As shown in the figure, we study the data corresponding to this request and the process after clicking to enter the details page. Case URL: aHR0cHM6Ly9jcmVkaXQuYWNsYS5vcmcuY24vY3JlZGl0L2xhd0Zpcm0/cGljQ2FwdGNoYVZlcmlmaWNhdGlvbj0ma2V5V29yZHM9
- Initially, there are font anti-climbing. In fact, after a series of analysis, it will be found that there are two types of cookie anti-climbing and des decryption. Next, look at the following analysis
Two, anti-debugging infinite debugger and console
- Anti-climbing 1: Unlimited debugger, open the Google developer tools, and use the infinite debugger as shown in the figure
- Anti-climbing 2: console console.clear / console.log anti-debugging, inject hook code and return directly to empty, or open a new tab to open it
console._clear=console.clear console.clear=function(){ return } console._log=console.log console.log=function(a){ return }
3. jsfuck generates cookies
- Anti-climbing 3: cookie anti-crawling, the first response of the web page returns the code of jsfunck to generate cookies, and the second request carries cookies to obtain normal data
- The html source code of the web page responding to the request for the first time is as follows, as shown in the figure is the jsfuck code
- The real code that removes
()
the de-obfuscated output to the console is shown in the figure, and a function self-executable code is generated at this time
- Analyze the logic of cookie generation by the js code in the above picture, and write the following code, in which the jsfuck code needs to remove the last self-executing parenthesis
- You also need to remove a self-executable parenthesis to make it non-self-executable, so that you can use
ctx.eval(new_js)
the method to output and obtain the source code, otherwise it will report an error missing window/document and other objects. More jsfuck code introduction
- Sort out the process and write the following code to parse jsfuck to obtain the cookie logic as follows
4. Des decryption details url suffix
- Anti-climbing 4: change of url suffix
- Click the breakpoint at the event position, and then debug
- Debug to the following position as shown in the figure, the standard des ecb decryption, directly use python to
from Crypto.Cipher import DES
decrypt, where the key is dynamic, you can get it in the response
Five, woff dynamic font anti-climbing
-
Anti-climbing 5: woff font encoding conversion, about the use of fontTools , about font anti-climbing introduction
-
Every time the webpage is refreshed, there will be a new set of ttf font files, that is
动态文件,动态编码,有规律的坐标
, CSS font anti-climbing belonging to the intermediate difficulty
-
Copy the ttf link to the browser to open, download the ttf file, and then go to https://font.qqe2.com/ to open the ttf file, as shown in the figure
-
For the same Chinese character
律
, let's compare the two ttf files, which correspond to different codes, that is to say编码是动态变化
(because the font file ttf is also dynamically changing)
-
Save the ttf file as an xml file according to the following code, and open the xml file to compare the same Chinese character, and
pip install fontTools
then conduct a comparative analysis, and find that although the codes are different, the x and y coordinates are the samefrom fontTools.ttLib import TTFont font = TTFont("./font.ttf") font.saveXML('./font.xml') font = TTFont("./font2.ttf") font.saveXML('./font2.xml')
-
That is to say, we only need to obtain the x/y coordinates and the font mapping relationship. For example
[{'[16, -93, 930, 808]': '律'}]
, each ttf font file only needs to obtain the x/y coordinates to obtain the corresponding Chinese characters. First, save a copy of the xy coordinates The relationship with font mapping, here we use Zhege's ddddocr to identify Chinese characters, the code is as follows
from PIL import ImageFont, Image, ImageDraw from io import BytesIO import ddddocr from fontTools.ttLib import TTFont def font_to_img(_code, filename): """将字体画成图片""" img_size = 1024 img = Image.new('1', (img_size, img_size), 255) draw = ImageDraw.Draw(img) font = ImageFont.truetype(filename, int(img_size * 0.7)) txt = chr(_code) x, y = draw.textsize(txt, font=font) draw.text(((img_size - x) // 2, (img_size - y) // 2), txt, font=font, fill=0) return img # 坐标与汉字对应 map_word = dict() ocr = ddddocr.DdddOcr() _font = TTFont("./font.ttf") for cmap_code, glyph_name in _font.getBestCmap().items(): # 坐标xy xy = [_font['glyf'][glyph_name].xMin, _font['glyf'][glyph_name].yMin, _font['glyf'][glyph_name].xMax, _font['glyf'][glyph_name].yMax] bytes_io = BytesIO() pil = font_to_img(cmap_code, "./font.ttf") pil.save(bytes_io, format="PNG") # 识别出的汉字 word = ocr.classification(bytes_io.getvalue()) map_word[str(xy)] = word with open(f"{ word}__{ xy[0]}.png", "wb") as f: f.write(bytes_io.getvalue()) print(map_word) # 编码与xy坐标对应的关系 extract_name = { } for extrat_name in _font.get('post').__dict__['extraNames']: extract_name[extrat_name] = [_font['glyf'][extrat_name].xMin, _font['glyf'][extrat_name].yMin, _font['glyf'][extrat_name].xMax, _font['glyf'][extrat_name].yMax] print(extract_name)