web端逆向经验、分析思路
前言
以下是看了鱼哥的公众号"咸鱼学python",和"网虫spider" 之后,加上一些自己的经验,总结出以下的js逆向的经验。看过《误杀》吗,里面有句话就是:当你看过1000部以上的电影,这世界上压根没有什么离奇的事情。
所以多看别人的分享案例,保持学习的状态,你可以不用自己去分析,但是一定要学习别人遇到问题时的分析思路
此篇博文会一直更新,把web端的爬虫经验分析够覆盖时下主流
1.js逆向调试流程
-
如果网页有跳转,必须勾选 preservelog 防止丢包
-
看一下有没有框架 右键查看框架源代码(弹出式登陆界面)
-
登陆尽量使用错误密码 防止跳转
-
查看关键登陆包 分析哪些参数是加密的
-
使用别的浏览器分析哪些参数是固定的值
-
初步猜测加密方法
-
搜索
-
直接搜索参数
-
pwd=
-
pwd =
-
pwd:
-
pwd :
-
密码框地方右键 检查 查看 id name type
-
找到加密的地方(重点)
-
调试
-
找出所有的加密代码
-
从最后一步开始写起,缺啥找啥
-
如果找的是函数的话 search 要带上 function xxx
-
如果看到加密的地方有个类,并且之后是用 prototype 把方法加在原生对象上的话,要把
所有加在原生对象上的方法都找出来 -
函数找多了没关系,只要不报错不会影响结果,但是不能找少了
2.rsa破解:
-
一般的rsa加密通常会先声明一个rsa对象
-
本地使用公钥加密即public key
-
通常有Encrypt关键字
-
加密后字符长度为128位或256位
结合以上套路可以帮助我们快速判断加密方式如何,便于我们理清解密思路。
rsa加密:
from Crypto.PublicKey import RSA # 导入模块 from Crypto.Cipher import PKCS1_v1_5 import base64 key = RSA.generate(2048) with open('prkey.pem', 'wb') as f: # 生成私钥文件 f.write(key.exportKey('PEM')) public = key.publickey() with open('pukey.pem', 'wb') as f: # 生成公钥文件 f.write(public.exportKey('PEM')) def encrypto(password): rsakey = RSA.importKey(open('pukey.pem').read()) cipher = PKCS1_v1_5.new(rsakey) result_encode = cipher.encrypt(password.encode()) print(result_encode) return result_encode def dencrypto(password): prkey = RSA.importKey(open('prkey.pem').read()) cipher = PKCS1_v1_5.new(prkey) result_encode = cipher.decrypt(password, 'ERROR') result = result_encode.decode() print(result) def encrypto_test(pk, password): public_key = f"-----BEGIN PUBLIC KEY-----\n{pk}\n-----END PUBLIC KEY-----" rsakey = RSA.importKey(public_key) cipher = PKCS1_v1_5.new(rsakey) result_encode = cipher.encrypt(password.encode()) cipher_text = base64.b64encode(result_encode) result = cipher_text.decode() print(result) return result if __name__ == "__main__": # 加解密测试 dencrypto(encrypto('geeker')) # 实际的加密逻辑案例 password = "123456" pk = """MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt0TDbDiNsw8r0mNI8XPl ZGEsElso/AzZcRcudolcoKyjs8kDixpKruiajS+/GYOGwrqhHpOgVBaQPDEHS0yi iU37SvWJ6cCvzHQRRdZtQfdygc9JdJyPXfNw3rWoMCHqSxNx9/hNtiUujBGvnLe6 ebbCOzqsNwIbjpNhb1AZ0V7sVwk22rTJ610GWJr/5MXILyy05ziAe09pjUf/0f7U rIEB/EG35DuvB65GDXZLjSTDs+5P1yh8rTGnFSra7OAPhnjxwmTYV2Y+RitiQYQF yMNerI0KQNKvd3NyjHq+A9s1CzOXkCGkIK4sTsJKjC5Ok7cEOdu7+YOMLtfREzcE MQIDAQAB""" encrypto_test(pk, password)
3.大厂加密都简单,安全防护之类的完全不靠js加密,靠的是风控
像某付{}宝,大厂高级的都是风控,加解密都是开胃菜,用一个大佬跟我说的话,当你把加解密破解之后,游戏才刚刚开始
4.补环境
1).window is not defined;
修改为: window = global或者,var window = {}
ASN1 is not define,尝试window = global
2).navigator is not defined
修改为: var navigator = {}
3).Cannot read property 'userAgent' of undefined
navigator.userAgent = 'xxxx'
4).Cannot read property 'body' of undefined:
这个是 document里面的。
修改为:document.body = {xxx(具体的某个参数)}
5).Cannot read property 'x' of undefined
缺少函数,具体缺少什么,可根据调试来添加。
6).Cannot read property 'href' of undefined
是 location.href
修改为:
window.location = {
"xxxx": {},
"href": "https://www.xxxx.com/",
(其他参数保持)
}
7).Cannot read property 'length' of undefined
具体原因是取值的时候,取到的是null。。。
具体调试可得知。
8).Cannot read property 'cookie' of undefined
var document = {
cookie:"xxxxxx"
}
9).
Object.getOwnPropertyDescriptor
var Navigator = function() {};
Navigator.prototype = {"platform": "win32"};
navigator = new Navigator();
不能写成:
var navigator1 = {
platform:"win32"
}
因为:
10).prototype 与 _ _ proto _ _
xxx.__proto__ == yyy.prototype
遇到不好补的直接用jsdom,补起来很繁琐时,用jsdom处理,npm install jsdom
11).userAgent is not defined
window.navigator = {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
12.补齐window.localStorage:
window.localStorage = { removeItem: function (key) { delete this[key] }, getItem: function (key) { return this[key] ? this[key]: null; }, setItem: function (key, value) { this[key] = "" + value; // 将数字转为字符串 }, };
13.canvas补齐:
document = { createElement: function() { return canvas } }; canvas = { getContext: function getContext() { return CanvasRenderingContext2D }, toDataURL: function toDataURL() { return "data:image/xxxx" }, }; CanvasRenderingContext2D = { arc: function arc() {}, stroke: function stroke() {}, fillText: function fillText() {}, };
14.document补齐
location = { "href": "https://www.w3school.com.cn/jsref/prop_anchor_href.asp", "origin": "https://www.w3school.com.cn", "protocol": "https:", } document = { createElement: function () { var loc = { href: "" }; var temp_href = loc.href; Object.defineProperty(loc, 'href', { // Hook loc.href,当为其赋值时,按下面的规则强制改变 get: function () { return temp_href }, set: function (val) { if (val.indexOf('http://') === 0 || val.indexOf('https://') === 0) { // 1.当值为http://或https://开头时,即为该值 temp_href = val; } else if (val.indexOf('//') === 0) { // 2.当值为//开头时,即为location.protocol加上该值 temp_href = location.protocol + val; } else if (val.indexOf('/') === 0) { // 3.当值为/开头时,即为location.origin加上该值 temp_href = location.origin + val; } else { // 4.除以上3种情况,即为location.href中最后一个/之前的值加上该值 var s = location.href temp_href = s.substring(0, s.lastIndexOf("/")+1) + val } return temp_href } }); return loc; } }
5.有eval语句体的,直接把eval改为console.log,在控制台输出查看
6.python实现aes加密,pip3 install pycryptodome
ECB 加密代码:
import base64 from Crypto.Cipher import AES class UseAES: """ AES 除了MODE_SIV模式key长度为:32, 48, or 64, 其余key长度为16, 24 or 32 详细见AES内部文档 CBC模式传入iv参数 本例使用常用的ECB模式 """ def __init__(self, key): if len(key) > 32: key = key[:32] self.key = self.to_16(key) @staticmethod def to_16(key): """ 转为16倍数的bytes数据 :param key: :return: """ key = bytes(key, encoding="utf8") while len(key) % 16 != 0: key += b'\0' return key # 返回bytes def aes(self): return AES.new(self.key, AES.MODE_ECB) # 初始化加密器 def encrypt(self, text): aes = self.aes() return str(base64.encodebytes(aes.encrypt(self.to_16(text))), encoding='utf8').replace('\n', '') # 加密 def decode_bytes(self, text): aes = self.aes() return str(aes.decrypt(base64.decodebytes(bytes( text, encoding='utf8'))).rstrip(b'\0').decode("utf8")) # 解密 if __name__ == '__main__': aes_test = UseAES("xianyuxuepython") a = aes_test.encrypt("Python") print(a) b = aes_test.decode_bytes(a) print(b)
cbc模式
#!/usr/bin/env python # -*- coding=utf-8 -*- import base64 from Crypto.Cipher import AES import random def pkcs7padding(text): """ 明文使用PKCS7填充 最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理 :param text: 待加密内容(明文) :return: """ bs = AES.block_size # 16 length = len(text) bytes_length = len(bytes(text, encoding='utf-8')) # tips:utf-8编码时,英文占1个byte,而中文占3个byte padding_size = length if(bytes_length == length) else bytes_length padding = bs - padding_size % bs # tips:chr(padding)看与其它语言的约定,有的会使用'\0' padding_text = chr(padding) * padding return text + padding_text def pkcs7unpadding(text): """ 处理使用PKCS7填充过的数据 :param text: 解密后的字符串 :return: """ length = len(text) unpadding = ord(text[length-1]) return text[0:length-unpadding] def encrypt(key, content): """ AES加密 key,iv使用同一个 模式cbc 填充pkcs7 :param key: 密钥 :param content: 加密内容 :return: """ key_bytes = bytes(key, encoding='utf-8') iv = key_bytes cipher = AES.new(key_bytes, AES.MODE_CBC, iv) # 处理明文 content_padding = pkcs7padding(content) # 加密 encrypt_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8')) # 重新编码 result = str(base64.b64encode(encrypt_bytes), encoding='utf-8') return result def decrypt(key, content): """ AES解密 key,iv使用同一个 模式cbc 去填充pkcs7 :param key: :param content: :return: """ key_bytes = bytes(key, encoding='utf-8') iv = key_bytes cipher = AES.new(key_bytes, AES.MODE_CBC, iv) # base64解码 encrypt_bytes = base64.b64decode(content) # 解密 decrypt_bytes = cipher.decrypt(encrypt_bytes) # 重新编码 result = str(decrypt_bytes, encoding='utf-8') # 去除填充内容 result = pkcs7unpadding(result) return result def get_key(n): """ 获取密钥 n 密钥长度 :return: """ c_length = int(n) source = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' length = len(source) - 1 result = '' for i in range(c_length): result += source[random.randint(0, length)] return result en_16 = 'abcdefgj10124567' encrypt_en = encrypt(aes_key, en_16) print(encrypt_en)
PKCS7模式:
import base64 from Crypto.Cipher import AES import random def pkcs7padding(text): """ 明文使用PKCS7填充 最终调用AES加密方法时,传入的是一个byte数组,要求是16的整数倍,因此需要对明文进行处理 :param text: 待加密内容(明文) :return: """ bs = AES.block_size # 16 length = len(text) bytes_length = len(bytes(text, encoding='utf-8')) # tips:utf-8编码时,英文占1个byte,而中文占3个byte padding_size = length if(bytes_length == length) else bytes_length padding = bs - padding_size % bs # tips:chr(padding)看与其它语言的约定,有的会使用'\0' padding_text = chr(padding) * padding return text + padding_text def pkcs7unpadding(text): """ 处理使用PKCS7填充过的数据 :param text: 解密后的字符串 :return: """ length = len(text) unpadding = ord(text[length-1]) return text[0:length-unpadding] def encrypt(key, content): """ AES加密 key,iv使用同一个 模式cbc 填充pkcs7 :param key: 密钥 :param content: 加密内容 :return: """ key_bytes = bytes(key, encoding='utf-8') iv = key_bytes cipher = AES.new(key_bytes, AES.MODE_CBC, iv) # 处理明文 content_padding = pkcs7padding(content) # 加密 encrypt_bytes = cipher.encrypt(bytes(content_padding, encoding='utf-8')) # 重新编码 result = str(base64.b64encode(encrypt_bytes), encoding='utf-8') return result def decrypt(key, content): """ AES解密 key,iv使用同一个 模式cbc 去填充pkcs7 :param key: :param content: :return: """ key_bytes = bytes(key, encoding='utf-8') iv = key_bytes cipher = AES.new(key_bytes, AES.MODE_CBC, iv) # base64解码 encrypt_bytes = base64.b64decode(content) # 解密 decrypt_bytes = cipher.decrypt(encrypt_bytes) # 重新编码 result = str(decrypt_bytes, encoding='utf-8') # 去除填充内容 result = pkcs7unpadding(result) return result def get_key(n): """ 获取密钥 n 密钥长度 :return: """ c_length = int(n) source = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' length = len(source) - 1 result = '' for i in range(c_length): result += source[random.randint(0, length)] return result
PBKDF2:
import hmac from hashlib import sha1, md5 import base64 from Crypto.Cipher import AES from binascii import a2b_hex, hexlify import hashlib def decrypt(decryptData: str, key: bytes, iv: bytes): # 解密函数 res = a2b_hex(decryptData) aes = AES.new(key, AES.MODE_CBC, iv) plain_text = aes.decrypt(res) def unpad(date): return date[0:-ord(date[-1])] return unpad(plain_text.decode(errors='ignore')) def hash_hmac(key, code): hmac_code = hmac.new(key.encode(), code.encode(), sha1).digest() return base64.b64encode(hmac_code).decode() def md5_hex(code): return md5(code.encode()).hexdigest() def PBKDF2(string): salt = "secret".encode() dk = hashlib.pbkdf2_hmac('sha256', string.encode(), salt, 1000) return hexlify(dk).decode() if __name__ == '__main__': text = '73cd58935455e66d8f9c676f7f45c88d7d27d02296f6fab0ff7c41088351ee2b08db87df48d6e7218fbac0eea8e639e0fa24ae64c6c31ece1a808d0db5b68b9c466ecf514faa4129eb661d68b012f06b5975e25eea5f381f957e71ecf3e97689d497b04f3a5bfd03e07f8682cf6480fd803c0e94173fcba5a7d3ae257f55e21d8ea822bdc589e42185e26ef145aeafabb5be0781cfa6c583622b5c8379b2a1066b173d311dffa3ebc7033e20f252c7593066899c7955efdefee904c46168dfde7d57bcb8362091907353bb0656e56c4466e5ec56b826e5fa6b857a3c6077e7755f9379ad82a17c7b3ec9b0ef40ebaff7cab21f48e4d54a8af135ba71d67ae5c5f2c6d00a3dafa8b0ff43fe30b2d62a4649ac534226c06a4d2ca4d3a4564a28eaa2958b057ae247e797f6df8552eeb3c50047998df0b0c53eeb83a2645b50b94953ab33b1370d51d43c84a955bff58ed6efb659a1dd1eda55fa8dc3f0d383303bb5d8018077870c46ed2708f7559f25a8c0ff3ced0fcd000a739e10846cc8cc437fdc022664cb63ee313cb43b53e3965bcbb77025b124ffbbf3ce49fd75f9a5afa322b65e0816b710f1f07374838cfca5e5edec2211348de61cd3acb989bda496e0e18a8569c5a39cd63c73b8fff635d853d6330e3e30a293253ac15a8b8810e5441a693e2c3b9d50afd4fb7ed673199355741a8cbbd5e9cfe8bcea2ffd6f537a24d3b6101935897de20211a4ad7404d9a5d9462276e0c422f8ac14b6b2dd6be85f12129a55fd5b648b604ed1f73c3b5d59b9ea802211dfaacb12d21f8c174fb5c0bf9476ab825a12a74fd870b19018b2fb69aecb122401ce9629e44df061eacd92ab038d5dad7671ff375c21091e7af004fda6a716a372d0b3bc500f843400f557a0f19d179b82061f82584a44542d7755e3b87e62648dde294764faebc10640ab2658dd7defff2c773140b9ea080ddca8c3691fa963ad64751b895345f4c8e827b02104e0b4c86b73be751a47fb36535305976a362b024914b31d3d39eda81128314d01f6e109880b675ea41b95720256e13a1' key_hex = PBKDF2("D23ABC@#56") iv_hex = PBKDF2("api/api3/bk/score/provide")[:32] print(key_hex) print(iv_hex) decrypt_text = decrypt(text, a2b_hex(key_hex), a2b_hex(iv_hex)) print(decrypt_text)
AES-CBC
输出 Hash
的示例代码
from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex class PrpCrypt(object): def __init__(self, key): self.key = key.encode('utf-8') self.mode = AES.MODE_CBC # 加密函数,如果text不足16位就用空格补足为16位, # 如果大于16当时不是16的倍数,那就补足为16的倍数。 def encrypt(self, text): text = text.encode('utf-8') cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF') # 这里密钥key 长度必须为16(AES-128), # 24(AES-192),或者32 (AES-256)Bytes 长度 # 目前AES-128 足够目前使用 length = 16 count = len(text) if count < length: add = (length - count) # \0 backspace # text = text + ('\0' * add) text = text + ('\0' * add).encode('utf-8') elif count > length: add = (length - (count % length)) # text = text + ('\0' * add) text = text + ('\0' * add).encode('utf-8') self.ciphertext = cryptor.encrypt(text) # 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题 # 所以这里统一把加密后的字符串转化为16进制字符串 return b2a_hex(self.ciphertext) # 解密后,去掉补足的空格用strip() 去掉 def decrypt(self, text): cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF') plain_text = cryptor.decrypt(a2b_hex(text)) # return plain_text.rstrip('\0') return bytes.decode(plain_text).rstrip('\0') if __name__ == '__main__': pc = PrpCrypt('jo8j9wGw%6HbxfFn') # 初始化密钥 key e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}') # 加密 d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==") # 解密 print("加密:", e) print("解密:", d)
AES-CBC
输出 Base64
的示例代码
from Crypto.Cipher import AES from binascii import b2a_hex, a2b_hex import base64 class PrpCrypt(object): def __init__(self, key): self.key = key.encode('utf-8') self.mode = AES.MODE_CBC # 加密函数,如果text不足16位就用空格补足为16位, # 如果大于16当时不是16的倍数,那就补足为16的倍数。 def encrypt(self, text): text = text.encode('utf-8') cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF') # 这里密钥key 长度必须为16(AES-128), # 24(AES-192),或者32 (AES-256)Bytes 长度 # 目前AES-128 足够目前使用 length = 16 count = len(text) if count < length: add = (length - count) # \0 backspace # text = text + ('\0' * add) text = text + ('\0' * add).encode('utf-8') elif count > length: add = (length - (count % length)) # text = text + ('\0' * add) text = text + ('\0' * add).encode('utf-8') self.ciphertext = cryptor.encrypt(text) return base64.b64encode(self.ciphertext).decode() # 解密后,去掉补足的空格用strip() 去掉 def decrypt(self, text): cryptor = AES.new(self.key, self.mode, b'0123456789ABCDEF') decryptByts = base64.b64decode(text) plain_text = cryptor.decrypt(decryptByts) return bytes.decode(plain_text).rstrip('\0') if __name__ == '__main__': pc = PrpCrypt('jo8j9wGw%6HbxfFn') # 初始化密钥 key e = pc.encrypt('{"code":200,"data":{"apts":[]},"message":"","success":true}') # 加密 d = pc.decrypt("lXgLoJQ3MAUdzLX+ORj5/pJlkRAU423JfyUKVd5IwfCSxw6d1mHwBdHV9p3kmKCYwNRmAIEWeb/9ypLCqTZ1FA==") # 解密 print("加密:", e) print("解密:", d)
更多的加密算法,有个老哥都实现了,git地址:https://github.com/Eeyhan/R-A-M-D-D3-S-M-H
7.css伪元素破解:
CSS中,::before 创建一个伪元素,其将成为匹配选中的元素的第一个子元素。常通过 content
属性来为一个元素添加修饰性的内容。此元素默认为行内元素。
8.发现有加密,搜索encrypt,JSON.parse,JSON.stringify,
CryptoJS 等相关的
9.断点后的变量保存到全局
- 选中变量, 右键 Evalute in console
- 在 console 中选中输出的内容, 右键 store as global variable
10.JSFuck 是使用 [
、]
、(
、)
、!
和 +
六种字符来表示原有的字符的
就像下面这样的对应关系:
false => ![]
true => !![]
undefined => [][[]]
NaN => +[![]]
0 => +[]
1 => +!+[]
2 => !+[]+!+[]
10 => [+!+[]]+[+[]]
Array => []
Number => +[]
String => []+[]
Boolean => ![]
JSFuck 的处理方法有以下几种:
document.write(xxx)
alert(xxx)
console.log(xxx)
11.eval加密
把一段字符串当做js代码去执行
eval(function(){alert(100);return 200})()
例子: 漫画柜,空中网 之后会单独写一篇漫画柜的解密。
12.变量名混淆
-
把变量名、函数名、参数名等,替换成没有语义,看着又很像的名字。
_0x21dd83、_0x21dd84、_0x21dd85
-
用十六进制文本去表示一个字符串
\x56\x49\x12\x23
-
利用JS能识别的编码来做混淆
JS是Unicode编码,本身就能识别这种编码。类似的一些变量名,函数名都可以用这个表示,并且调用。
类似: \u6210\u529f表示中文字符(成功)。 类似: \u0053\u0074\u0072\u0069\u006e\u0067.\u0066\u0072\u006f\u006d\u0043\u0068\u0061\u0072\u0043\u006f\u0064\u0065就代表String.fromCharCode 类似: ('')['\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72']['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65'];效果等同于String.fromCharCode
-
把一大堆方法名、字符串等存到数组中,这个数组可以是上千个成员。然后调用的时候,取数组成员去用
var arr = ["Date","getTime"]; var time = new window[arr[0]]()[arr[1]](); console.log(time);
-
字符串加密后发送到前端,然后前端调用对应的函数去解密,得到明文
var arr = ['xxxx'] // 定义的解密函数 function dec(str){ return 'push' } test[dec(arr[0])](200);
13.控制流平坦化
将顺序执行的代码混淆成乱序执行,并加以混淆
以下两段代码的执行结果是相同的:
// 正常形态 function test(a){ var b = a; b += 1; b += 2; b += 3; b += 4; return a + b } // 乱序形态 //(这里比较简单,在很多加密网站上case 后面往往不是数字或字符串,而是类似 YFp[15][45][4]这样的对象,相当恶心) function test1(a){ var arr = [1,2,3,4,5,6] for(var i = 0, i < arr.lenght, i++){ switch (arr[i]) { case 4: b += 3; break; case 2: b += 1; break; case 1: var b = a; break; case 3: b += 2; break; case 6: return a + b case 5: b += 4; break; } } } // 结果都是30 但是test1看着费劲 console.log(test1(10)); console.log(test(10));
14.压缩代码
把多行代码压缩成一行
function test(a){ var b = a; var c = b + 1; var d = b + 2; var e = b + 3; var f = b + 4; return e + f } // 压缩一下 function test1(a){ var b,c,d,e,f return f = (e = (d = ( c = (b = a,b + 1),b + 2),b + 3),b + 4),e + f }
15.长得像base64的字符串,但是解密失败的,要嘛aes/des,rsa,如果不是,尝试用lzstring库加解密
16.有关atob相关的
在浏览器中base64编码转换使用的是
_0x1c0cdf = _0xcbc80b['atob'](_0x1c0cdf)
,
在nodejs调试的时候使用的是
Buffer.from(_0x1c0cdf,"base64").toString()
17.判断数据是不是由js生成或异步加载的。
-
第一种,右键查看「网页源代码」,之后在打开的网页源码的界面搜索我们想要的数据是否在其中就可以判断了。
-
第二种,关闭网页的js加载功能,查看网页我们需要的数据是否能够顺利加载或者查看数据是否完整,步骤也非常简单
第二种:
chrome浏览器访问某网站,点击哪个锁图片
选择网站设置,然后把js那一栏改为禁止
刷新页面即可验证
18.node环境调试
用 Python 调用的 Node 环境不支持 document 这类浏览器属性,在调试的时候需要将它去除或在 Node 下执行不报错即可
19.找加密字段时
如果直接搜搜不到或者搜出来结果很多,可以搜跟这个加密字段相关的其他参数,因为一般情况下它们都是一起提交的,所以一般都会写在一块
20.在堆栈里,发现找不到js文件时,
参考链接:https://stackoverflow.com/questions/60369755/could-not-load-content-for-webpack-source-file-in-chrome-sources-tab这个应该是 webpack 的最小化生产模式导致在devtool模式的时候找不到文件映射
I was getting exactly the same problem, same error message etc when trying to debug typescript / html in Google Chrome.
The solution is to empty your cache.
Press Control + H to load up your browser history, and press the Clear Data button.
The try pressing Control + O or Control + P to load/select a source file again
通过快捷键 ctrl + p 重新加载文件
21.hook eval
window.__cr_eval = window.eval; var myeval = function (src) { console.log('eval:', src); return window.__cr_eval(src) }; var _myeval = myeval.bind(null); _myeval.toString = window.__cr_eval.toString; Object.defineProperty(window, 'eval', {value: _myeval});
22.去除无限debug
//去除无限debugger Function.prototype.__constructor_back = Function.prototype.constructor; Function.prototype.constructor = function() { if(arguments && typeof arguments[0]==='string'){ //alert("new function: "+ arguments[0]); if("debugger" === arguments[0]){ //arguments[0]="console.log(\"anti debugger\");"; //arguments[0]=";"; return } } return Function.prototype.__constructor_back.apply(this,arguments); }
23.ob混淆,99%的加密结果都在代码结尾
结语
没有结束,会持续更新,同时app端的逆向也会出一个同类型的经验博文持续更新