当前位置: 首页 > news >正文

猿人学14题详解

目测重点在于cookie:mz和m

获取mz.js: https://match.yuanrenxue.com/static/match/match14/m.js

获取设置m: https://match.yuanrenxue.com/api/match/14/m

一、还原16进制

const fs = require('fs');
const parser = require('@babel/parser');
const generator = require('@babel/generator').default;const jsCode = fs.readFileSync('./mz.js', {encoding: 'utf-8'})let ast = parser.parse(jsCode);//parse 一下就可以了let code = generator(ast, {minified: true, jsescOption: {minimum: true}}).code;
ast = parser.parse(code);
code = generator(ast).code;
fs.writeFile('./mz1.js', code, (err) => {
});

初步看到mz赋值位置:

 n["Nu" + "mK" + "J"] = "mz" + "=", n["ZD" + "Kb" + "v"] = ";p" + "at" + "h=" + "/", n["Dn" + "NJ" + "W"] = "/a" + "pi" + "/m" + "at" + "ch" + "/1" + "4/" + "m", n["tl" + "pB" + "r"] = function (K, Y) {

二、字符串拼接

目标:n["cW" + "QT" + "T"] -> n["cWQTT"]
import json
import osdef concat_obj_property_name(node):if type(node) == list:for item in node:concat_obj_property_name(item)returnelif type(node) != dict:return# 捕获一个二元运算节点if 'type' in node and node['type'] == 'BinaryExpression':if not (node['left']['type'] == 'Literal' and node['right']['type'] == 'Literal'):concat_obj_property_name(node['left'])concat_obj_property_name(node['right'])if node['left']['type'] == 'Literal' and node['right']['type'] == 'Literal':# 构造新节点new_node = {'type': 'Literal', 'value': node['left']['value'] + node['right']['value']}node.clear()node.update(new_node)returnfor key in node.keys():concat_obj_property_name(node[key])if __name__ == '__main__':with open('mz1.json', 'r', encoding='utf8') as f:data = json.loads(f.read())concat_obj_property_name(data)with open('mz2.json', 'w', encoding='utf8') as f:f.write(json.dumps(data))os.system('/usr/local/bin/node JsonToJs mz2.json mz2.js')

三、数值运算还原

目标:window['n'] = 7317 + -8779 + 1462; -> window['n'] = 0;

使用Python处理要考虑的情况太多。使用js更方便

const fs = require('fs');
//js转AST代码
const parser = require('@babel/parser');
//遍历ASR节点
const traverse = require('@babel/traverse').default;
//用来判断节点类型产生新的节点
const t = require('@babel/types');
//用来把AST转换成js代码
const generator = require('@babel/generator').default;
const jscode = fs.readFileSync("./mz2.js", {encoding: "utf-8"
});const visitor = {"BinaryExpression"(path) {let left = path.node.left;let right = path.node.right;if (left.type == "NumericLiteral" | left.type == "UnaryExpression" && right.type == "NumericLiteral" | right.type == "UnaryExpression") {path.replaceWith(t.valueToNode(path.evaluate().value));}}
}const revertUnaryExpression = {"UnaryExpression"(path) {let argument = path.node.argument;if (argument.type == 'NumericLiteral' | argument.type == 'UnaryExpression' && generator(path.node).code.indexOf(' -') != -1) {path.replaceWith(t.valueToNode(eval(generator(path.node).code)));}}
}
let ast = parser.parse(jscode);
for (let i = 0; i < 10; i++) {traverse(ast, visitor);
}
traverse(ast, revertUnaryExpression)let code = generator(ast).code;
fs.writeFile('./mz3.js', code, (err) => {
});

四、对象调用还原

个人想法:这一步才是备而后动-勿使有变这个题目的精髓。

    var L = {};L['aKzhL'] = function (S, P) {return S + P;}var G = L;function C(S, P) {var F = G['aKzhL'](G['IboVR'](65535, S), G['IboVR'](65535, P));return G['DNzZE'](G['QpEsx'](G['aKzhL'](G['imxsL'](G['Ggivm'](S, 16), G['Ggivm'](P, 16)), G['Ggivm'](F, 16)), 16), G['IboVR'](65535, F));}

以L来说,在后面替换并未直接使用,而是使用var G = L;进行替换,这还只是针对一个块语句来说,若是放到全局,L不知道被污染多少次了。观察结构,可以在块语句中进行替换。

目标:还原前如上述代码。

            还原后:

    function C(S, P) {var F = (65535 & S) + (65535 & P);return (S >> 16) + (P >> 16) + (F >> 16) << 16 | 65535 & F;}
import copy
import json
import osobj_name_list = []
obj_property_dict = {}def get_property_dict(node):global obj_property_dictif type(node) == list:for item in node:get_property_dict(item)returnelif type(node) != dict:return# 因为存在变量更新的情况,所以不能遍历全文,在一个块语句中就做替换if 'type' in node and node['type'] == 'BlockStatement':try:# 观察发现,代码中都是 赋值-表达式语句-赋值 这三种格式if len(node['body']) >= 3 and \node['body'][0]['type'] == 'VariableDeclaration' and \node['body'][1]['type'] == 'ExpressionStatement' and \node['body'][2]['type'] == 'VariableDeclaration':obj_property_dict.clear()if 'init' in node['body'][2]['declarations'][0] and \node['body'][2]['declarations'][0]['init']['type'] == 'Identifier':obj_name = node['body'][2]['declarations'][0]['id']['name']if obj_name not in obj_property_dict:obj_property_dict[obj_name] = {}for i in node['body'][1]['expression']['expressions']:if i['type'] == 'AssignmentExpression':property_name = i['left']['property']['value']obj_property_dict[obj_name][property_name] = i['right']obj_property_reload(node)node['body'][2]['declarations'][0]['init'] = {'type': 'Literal', 'value': 'Nothing'}node['body'] = node['body'][2:]except KeyError as e:print('error', e, node['body'][2]['declarations'])for key in node.keys():get_property_dict(node[key])# 对象调用还原
def obj_property_reload(node):if type(node) == list:for item in node:obj_property_reload(item)returnelif type(node) != dict:returntry:if node['type'] == 'MemberExpression':# 处理形似:_0x5243e3['UhBgk']return '666'try:obj_name = node['object']['name']obj_property_name = node['property']['value']new_node = obj_property_dict[obj_name][obj_property_name]if new_node['type'] != 'FunctionExpression':node.clear()node.update(new_node)except Exception:pass# 捕获一个函数调用节点,且子节点callee的类型是一个MemberExpressionif node['type'] == 'CallExpression' and node['callee']['type'] == 'MemberExpression':argument_list = node['arguments']for para in argument_list:if para['type'] == 'CallExpression':  # 递归调用obj_property_reload(para)obj_name = node['callee']['object']['name']obj_property_name = node['callee']['property']['value']  # 获取需要调用的对象属性名称function_node = obj_property_dict[obj_name][obj_property_name]  # 获取函数定义节点,即对象的属性值(该属性值是一个函数定义)# 获取形参param_list = [item['name'] for item in function_node['params']]# 获取实参param_argument_dict = dict(zip(param_list, argument_list))return_node = copy.deepcopy(function_node['body']['body'][0])# print(return_node)if return_node['argument']['type'] == 'BinaryExpression' or \return_node['argument']['type'] == 'LogicalExpression':if return_node['argument']['left']['type'] == 'Identifier':return_node['argument']['left'] = param_argument_dict[return_node['argument']['left']['name']]if return_node['argument']['right']['type'] == 'Identifier':return_node['argument']['right'] = param_argument_dict[return_node['argument']['right']['name']]node.clear()node.update(return_node['argument'])elif return_node['argument']['type'] == 'CallExpression':if return_node['argument']['callee']['type'] != 'MemberExpression':function_name = return_node['argument']['callee']['name']if function_name in param_argument_dict:return_node['argument']['callee'] = param_argument_dict[function_name]for i in range(len(return_node['argument']['arguments'])):if return_node['argument']['arguments'][i]['type'] == 'Identifier':argument_name = return_node['argument']['arguments'][i]['name']return_node['argument']['arguments'][i] = param_argument_dict[argument_name]node.clear()node.update(return_node['argument'])except Exception as e:print('???', e)for key in node.keys():obj_property_reload(node[key])if __name__ == '__main__':with open('mz3.json', 'r', encoding='utf8') as f:data = json.loads(f.read())get_property_dict(data)print(obj_property_dict.keys())with open('mz4.json', 'w', encoding='utf8') as f:f.write(json.dumps(data))os.system('/usr/local/bin/node JsonToJs mz4.json mz4.js')

五、控制流平坦化

import json
import osdef sort_code(node):if type(node) == list:try:if len(node) == 2 and node[1]['type'] == 'WhileStatement' and node[0]['type'] == 'VariableDeclaration':for i in node[0]['declarations']:if i['type'] == 'VariableDeclarator' and i['init'] and \i['init']['type'] == 'CallExpression':sort_list = i['init']['callee']['object']['value'].split('|')cases_list = node[1]['body']['body'][0]['cases']result_list = [cases_list[int(i)]['consequent'][0] for i in sort_list]node.clear()node.extend(result_list)except (KeyError, TypeError):for item in node:sort_code(item)returnelif type(node) == dict:for key in node.keys():sort_code(node[key])returnelse:returnfor item in node:sort_code(item)if __name__ == '__main__':with open('mz5.json', 'r', encoding='utf8') as f:data = json.loads(f.read())sort_code(data)with open('mz6.json', 'w', encoding='utf8') as f:f.write(json.dumps(data))os.system('/usr/local/bin/node JsonToJs mz6.json mz6.js')

经过以上几个步骤,逻辑已经基本清晰:

  function E(K) {function d(h, b) {var D = b;var I = _n('jsencrypt');var u = new I();var Q = u['encode'](h, D);// if (m5['toString']()['indexOf']('\n') != -(1507 + -311 * -11 + -4927)) while (!![]) {//   console['log'](x['pSnMY'](x['pSnMY'](x['pSnMY']('生而', '为虫'), ',我'), '很抱') + '歉');// }return Q;}return result = d(K, K), result;}let a, p;a = Date['parse'](new Date()) * 8;p = E(parseInt(a / 8));  //rsa加密let b = Date['parse'](new Date());let aa = m5(p);let bb = m5(b);let d = 'Mozilla,Netscape,5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36,[object NetworkInformation],true,,[object Geolocation],8,zh-CN,zh-CN,zh,0,[object MediaCapabilities],[object MediaSession],[object MimeTypeArray],true,[object Permissions],MacIntel,[object PluginArray],Gecko,20030107,[object UserActivation],Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36,Google Inc.,,[object DeprecatedStorageQuota],[object DeprecatedStorageQuota],875,0,25,1440,30,900,[object ScreenOrientation],30,1440,[object DOMStringList],function assign() { [native code] },,match.yuanrenxue.com,match.yuanrenxue.com,https://match.yuanrenxue.com/match/14,https://match.yuanrenxue.com,/match/14,,https:,function reload() { [native code] },function replace() { [native code] },,function toString() { [native code] },function valueOf() { [native code] }'let b64_zw = 'TW96aWxsYSxOZXRzY2FwZSw1LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTBfMTVfNykgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzExMC4wLjAuMCBTYWZhcmkvNTM3LjM2LFtvYmplY3QgTmV0d29ya0luZm9ybWF0aW9uXSx0cnVlLCxbb2JqZWN0IEdlb2xvY2F0aW9uXSw4LHpoLUNOLHpoLUNOLHpoLDAsW29iamVjdCBNZWRpYUNhcGFiaWxpdGllc10sW29iamVjdCBNZWRpYVNlc3Npb25dLFtvYmplY3QgTWltZVR5cGVBcnJheV0sdHJ1ZSxbb2JqZWN0IFBlcm1pc3Npb25zXSxNYWNJbnRlbCxbb2JqZWN0IFBsdWdpbkFycmF5XSxHZWNrbywyMDAzMDEwNyxbb2JqZWN0IFVzZXJBY3RpdmF0aW9uXSxNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMTEwLjAuMC4wIFNhZmFyaS81MzcuMzYsR29vZ2xlIEluYy4sLFtvYmplY3QgRGVwcmVjYXRlZFN0b3JhZ2VRdW90YV0sW29iamVjdCBEZXByZWNhdGVkU3RvcmFnZVF1b3RhXSw4NzUsMCwyNSwxNDQwLDMwLDkwMCxbb2JqZWN0IFNjcmVlbk9yaWVudGF0aW9uXSwzMCwxNDQwLFtvYmplY3QgRE9NU3RyaW5nTGlzdF0sZnVuY3Rpb24gYXNzaWduKCkgeyBbbmF0aXZlIGNvZGVdIH0sLG1hdGNoLnl1YW5yZW54dWUuY29tLG1hdGNoLnl1YW5yZW54dWUuY29tLGh0dHBzOi8vbWF0Y2gueXVhbnJlbnh1ZS5jb20vbWF0Y2gvMTQsaHR0cHM6Ly9tYXRjaC55dWFucmVueHVlLmNvbSwvbWF0Y2gvMTQsLGh0dHBzOixmdW5jdGlvbiByZWxvYWQoKSB7IFtuYXRpdmUgY29kZV0gfSxmdW5jdGlvbiByZXBsYWNlKCkgeyBbbmF0aXZlIGNvZGVdIH0sLGZ1bmN0aW9uIHRvU3RyaW5nKCkgeyBbbmF0aXZlIGNvZGVdIH0sZnVuY3Rpb24gdmFsdWVPZigpIHsgW25hdGl2ZSBjb2RlXSB9';m = m5(gee(aa, bb, c, d, e, b64_zw)) + '|' + b + '|' + a + '|';return m

但是直接运行还是会陷入死循环,需要手动处理如:补环境,干掉格式检查,干掉本地环境检查。如以下示例:

// eval('delete document'), eval('delete window');
// bp = eval('CanvasCaptureMediaStreamTrack');
// global替换为Node环境下不存在的属性如:f**e['you']
try {global && (cl[cs >>> 2] &= 25 << 32 - cs % 4 * 8, cl['length'] = Math['ceil'](cs / 4));
} catch (cM) {cM[cs >>> 2] &= 4294967295 << 32 - cs % 4 * 8, cM['length'] = Math['ceil'](cs / 4);
}

经过以上操作,发现还缺少v14和v142参数,是在m.js文件中进行的赋值,又发现每次请求,m.js中的大数组是随机变化的。

window[$_0x3469('\x30\x78\x31\x32\x35', '\x65\x45\x30\x5a')] = '\x35\x37\x6f' + '\x38\x75\x33' + '\x70\x6b\x62' + '\x74';
window[$_0x3469('\x30\x78\x33\x34', '\x66\x56\x53\x75') + '\x32'] = $_0x3469('\x30\x78\x33\x31', '\x49\x44\x69\x5a') + '\x33\x36\x35' + $_0x3469('\x30\x78\x37\x34', '\x23\x64\x73\x53') + '\x32\x34';

 so等到需要时动态请求即可:

def get_v():"""get v14 and v142:return:"""res = session.get('https://match.yuanrenxue.com/api/match/14/m')v = re.findall("window\[\${0,1}.*?=(\${0,1}.*?);", res.text)if len(v) != 2:get_v()with open('./m.js', 'wb') as f:f.write(res.content)os.system('/usr/local/bin/node JsToJson m.js m.json')with open('./m.json', 'r', encoding='utf8') as f:node = json.loads(f.read())# 提取数组还原的代码及还原代码中的常量,其它代码无用array_revert_node = {'type': 'Program','body': node['body'][:3],'sourceType': 'script'}with open('m_array_revert.json', 'w', encoding='utf8') as f:f.write(json.dumps(array_revert_node))os.system('/usr/local/bin/node JsonToJs m_array_revert.json m_array_revert.js')return v

完整代码:

py:

import json
import os
import re
import subprocess
import execjs
import requestsnode = execjs.get()session = requests.session()headers = {'User-Agent': 'yuanrenxue.project'}
sum_num = 0def login():data = {'username': 'lllll','pwd': '********'}session.post('https://match.yuanrenxue.com/api/login', data=data)session.get('https://match.yuanrenxue.com/api/loginInfo')def get_v():"""get v14 and v142:return:"""res = session.get('https://match.yuanrenxue.com/api/match/14/m')v = re.findall("window\[\${0,1}.*?=(\${0,1}.*?);", res.text)if len(v) != 2:get_v()with open('./m.js', 'wb') as f:f.write(res.content)os.system('/usr/local/bin/node JsToJson m.js m.json')with open('./m.json', 'r', encoding='utf8') as f:node = json.loads(f.read())array_revert_node = {'type': 'Program','body': node['body'][:3],'sourceType': 'script'}with open('m_array_revert.json', 'w', encoding='utf8') as f:f.write(json.dumps(array_revert_node))os.system('/usr/local/bin/node JsonToJs m_array_revert.json m_array_revert.js')return vdef get_cookie(page_num, v):with open('m_array_revert.js', 'r', encoding='utf-8') as f:ctx = node.compile(f.read())v = [ctx.eval(i) for i in v]p = subprocess.Popen(['/usr/local/bin/node', './mz6.js', str(page_num), v[0], v[1]], stdout=subprocess.PIPE)m = p.stdout.read().decode('UTF-8').replace('\n', '')cookies = {'mz': 'TW96aWxsYSxOZXRzY2FwZSw1LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTBfMTVfNykgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzExMC4wLjAuMCBTYWZhcmkvNTM3LjM2LFtvYmplY3QgTmV0d29ya0luZm9ybWF0aW9uXSx0cnVlLCxbb2JqZWN0IEdlb2xvY2F0aW9uXSw4LHpoLUNOLHpoLUNOLHpoLDAsW29iamVjdCBNZWRpYUNhcGFiaWxpdGllc10sW29iamVjdCBNZWRpYVNlc3Npb25dLFtvYmplY3QgTWltZVR5cGVBcnJheV0sdHJ1ZSxbb2JqZWN0IFBlcm1pc3Npb25zXSxNYWNJbnRlbCxbb2JqZWN0IFBsdWdpbkFycmF5XSxHZWNrbywyMDAzMDEwNyxbb2JqZWN0IFVzZXJBY3RpdmF0aW9uXSxNb3ppbGxhLzUuMCAoTWFjaW50b3NoOyBJbnRlbCBNYWMgT1MgWCAxMF8xNV83KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMTEwLjAuMC4wIFNhZmFyaS81MzcuMzYsR29vZ2xlIEluYy4sLFtvYmplY3QgRGVwcmVjYXRlZFN0b3JhZ2VRdW90YV0sW29iamVjdCBEZXByZWNhdGVkU3RvcmFnZVF1b3RhXSw4NzUsMCwyNSwxNDQwLDMwLDkwMCxbb2JqZWN0IFNjcmVlbk9yaWVudGF0aW9uXSwzMCwxNDQwLFtvYmplY3QgRE9NU3RyaW5nTGlzdF0sZnVuY3Rpb24gYXNzaWduKCkgeyBbbmF0aXZlIGNvZGVdIH0sLG1hdGNoLnl1YW5yZW54dWUuY29tLG1hdGNoLnl1YW5yZW54dWUuY29tLGh0dHBzOi8vbWF0Y2gueXVhbnJlbnh1ZS5jb20vbWF0Y2gvMTQsaHR0cHM6Ly9tYXRjaC55dWFucmVueHVlLmNvbSwvbWF0Y2gvMTQsLGh0dHBzOixmdW5jdGlvbiByZWxvYWQoKSB7IFtuYXRpdmUgY29kZV0gfSxmdW5jdGlvbiByZXBsYWNlKCkgeyBbbmF0aXZlIGNvZGVdIH0sLGZ1bmN0aW9uIHRvU3RyaW5nKCkgeyBbbmF0aXZlIGNvZGVdIH0sZnVuY3Rpb24gdmFsdWVPZigpIHsgW25hdGl2ZSBjb2RlXSB9','m': m + str(page_num)}print(v)print(cookies)return cookiesdef get_page_info():global sum_numurl = 'https://match.yuanrenxue.com/api/match/14?'for i in range(1, 6):v = get_v()cookies = get_cookie(i, v)res = session.get(f'{url}page={i}', headers={'User-Agent': 'yuanrenxue.project'}, cookies=cookies).json()for j in res['data']:sum_num += j['value']if __name__ == '__main__':login()get_page_info()print(sum_num)

js:

GOOD-GOOD-STUDY/mz6.js at master · tianmingbo/GOOD-GOOD-STUDY · GitHub

http://www.lryc.cn/news/12847.html

相关文章:

  • Allegro如何快速把推挤的走线变平滑操作指导
  • nginx基础学习
  • 【HDFS】FsDatasetImpl#recoverClose方法
  • 加油站会员管理小程序实战开发教程15 完结篇
  • 学习 Python 之 Pygame 开发坦克大战(五)
  • 【ROS】Windows系统安装ROS体验
  • 第1讲-初步认识数据库系统(测试题总结)
  • 进程-操作系统结构
  • 【网络原理6】数据链路层协议——以太网
  • 组合数学原理与例题
  • 【机器学习 深度学习】通俗讲解集成学习算法
  • 汉字----dgfont
  • C# chart绘图 鼠标响应
  • 结构体与引用
  • 13.罗马数字转整数
  • JVM垃圾回收机制
  • Java File类、IO流、Properties属性类
  • MySQL备份恢复(十二)
  • 【Java|golang】1792. 最大平均通过率---封装最小堆
  • PHP 页面静态化
  • 【Python】进制、计算机中的单位、编码、数据类型、索引、字符串切片、字符串的功能方法
  • 基于android的无人健身房
  • 带你Java基础入门
  • VNCTF 2023 - Web 象棋王子|电子木鱼|BabyGo Writeups
  • 「JVM 编译优化」插入式注解处理器(自定义代码编译检查)
  • 一文彻底理解大小端和位域 BIGENDIAN LITTLEENDIAN
  • 面试准备知识点与总结——(虚拟机篇)
  • spring cloud 集成 seata 分布式事务
  • k8s篇之概念介绍
  • JavaScript学习第1天:浏览器组成、JS的组成、变量、数据类型转化、运算符、while和do...while循环