[817]JS加密--基础总结

2022-04-13 15:00:21 浏览数 (1)

文章目录
  • 常用的加密有哪些?
  • 学习资源推荐
  • 基础流程
  • 加密方法
    • RSA加密
    • 微型加密算法(XXTEA)
    • MD5加密
  • JS加密常见混淆总结
    • eval加密
    • 变量名混淆
    • 控制流平坦化
    • 压缩代码
  • Python实现加密方法合集

常用的加密有哪些?

对称加密(加密解密密钥相同):DES、DES3、AES 非对称加密(分公钥私钥):RSA 信息摘要算法/签名算法:MD5、HMAC、SHA

学习资源推荐

冷月大佬的博客 : https://lengyue.me/ 突破前端反调试–阻止页面不断debugger :https://segmentfault.com/a/1190000012359015 岚光的JavaScript反调试和混淆 :https://0x0d.im/archives/javascript-anti-debug-and-obfuscator.html

基础流程

以下是可以参考的调试流程(面向新手):

  1. 如果网页有跳转,必须勾选 preservelog 防止丢包
  2. 看一下有没有框架 右键查看框架源代码
  3. 登陆的话尽量使用错误密码 防止跳转
  4. 查看关键登陆包 分析哪些参数是加密的
  5. 使用别的浏览器分析哪些参数是固定的值
  6. 初步猜测加密方法
  7. 搜索(md5,aes,des,tripedes,rsa,encrypt,setpubkey,setpublickey)
  • 直接搜索参数
    • pwd=
    • pwd =
    • pwd:
    • pwd :
  • 密码框地方右键 检查 查看 id name type
  • 原生js方法获取
代码语言:javascript复制
doucumnet.getElementById[“”].value
doucumnet.getElementByName[“”][0].value
  • jQuery获取
代码语言:javascript复制
alert($(“#id”).val());
alert($(“input[type=’password’]”).val());
  1. 找到加密的地方(重点)
  2. 调试
  3. 找出所有的加密代码
  • 从最后一步开始写起,缺啥找啥
  • 如果找的是函数的话 search 要带上 function xxx
  • 如果看到加密的地方有个类,并且之后是用 prototype 把方法加在原生对象上的话,要把所有加在原生对象上的方法都找出来
  • 函数找多了没关系,只要不报错不会影响结果,但是不能找少了
  • 直接保存整页JS浏览器调试

加密方法

RSA加密

找了一些简单网站,查看了对应的RSA加密的方法,总结了以下套路:

  • 一般的rsa加密通常会先声明一个rsa对象
  • 本地使用公钥加密即public key,服务器上用私钥解密
  • 通常有Encrypt关键字
  • 加密后字符长度为128位或256位

结合以上套路可以帮助我们快速判断加密方式如何,便于我们理清解密思路。

微型加密算法(XXTEA)

“微型加密算法(TEA)及其相关变种(XTEA,Block TEA,XXTEA)都是分组加密算法,它们很容易被描述,实现也很简单(典型的几行代码)。 XXTEA是其最新的变种,于1998年提出。目前还没有人找到对其进行攻击的方法,是对前面一些变种的改进。XXTEA 算法很安全,而且非常快速,非常适合应用于 Web 开发中。 以上引用自https://my.oschina.net/mickelfeng/blog/109388

MD5加密
  • md5 hash的结果是固定不变的
  • md5 hash 后的结果为16位或32位字母数字混合的结果

JS加密常见混淆总结

eval加密
  • 把一段字符串当做js代码去执行
代码语言:javascript复制
eval(function(){alert(100);return 200})()

例子: 漫画柜,空中网 之后会单独写一篇漫画柜的解密。

变量名混淆
  • 把变量名、函数名、参数名等,替换成没有语义,看着又很像的名字。
代码语言:javascript复制
_0x21dd83、_0x21dd84、_0x21dd85
  • 用十六进制文本去表示一个字符串
代码语言:javascript复制
x56x49x12x23
  • 利用JS能识别的编码来做混淆

JS是Unicode编码,本身就能识别这种编码。类似的一些变量名,函数名都可以用这个表示,并且调用。

代码语言:javascript复制
类似:
u6210u529f
表示中文字符(成功)。

类似:
u0053u0074u0072u0069u006eu0067.u0066u0072u006fu006du0043u0068u0061u0072u0043u006fu0064u0065
就代表String.fromCharCode

类似:
('')['x63x6fx6ex73x74x72x75x63x74x6fx72']['x66x72x6fx6dx43x68x61x72x43x6fx64x65'];
效果等同于String.fromCharCode
  • 把一大堆方法名、字符串等存到数组中,这个数组可以是上千个成员。然后调用的时候,取数组成员去用
代码语言:javascript复制
var arr = ["Date","getTime"];
var time = new window[arr[0]]()[arr[1]]();
console.log(time);
  • 字符串加密后发送到前端,然后前端调用对应的函数去解密,得到明文
代码语言:javascript复制
var arr = ['xxxx']

// 定义的解密函数
function dec(str){
  return 'push'
}
test[dec(arr[0])](200);
控制流平坦化

将顺序执行的代码混淆成乱序执行,并加以混淆

以下两段代码的执行结果是相同的:

代码语言:javascript复制
// 正常形态
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));
压缩代码
  • 把多行代码压缩成一行
代码语言:javascript复制
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
}

Python实现加密方法合集

其实上面的步骤不一定都要去手动扣JS, 我们的大Python已经为我们造好了轮子,如果可以判断js的加密没有做其他的更改,我们就可以使用造好的轮子直接实现对应的加密。

所以这里给大家推荐一个大佬写的加密代码合集(我就不献丑了),记得给大佬来个star GitHub地址:

代码语言:javascript复制
https://github.com/dhfjcuff/R-A-M-D-D3-S-M-H/blob/master/RSA-AES-MD5-DES-DES3-MD5-SHA-HMAC.py

内容如下:

代码语言:javascript复制
# -*- coding:utf-8 -*-
import base64
import rsa
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
from pyDes import des, CBC, PAD_PKCS5
from Crypto.Cipher import DES3
import hashlib
import hmac


class USE_AES:
    """
    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)

    def to_16(self, key):
        """
        转为16倍数的bytes数据
        :param key:
        :return:
        """
        key = bytes(key, encoding="utf8")
        while len(key) % 16 != 0:
            key  = b''
        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 decodebytes(self, text):
        aes = self.aes()
        return str(aes.decrypt(base64.decodebytes(bytes(
            text, encoding='utf8'))).rstrip(b'').decode("utf8"))  # 解密


class USE_RSA:
    """
    生成密钥可保存.pem格式文件
    1024位的证书,加密时最大支持117个字节,解密时为128;
    2048位的证书,加密时最大支持245个字节,解密时为256。
    加密大文件时需要先用AES或者DES加密,再用RSA加密密钥,详细见文档
    文档:https://stuvel.eu/files/python-rsa-doc/usage.html#generating-keys
    """
    def __init__(self, number=1024):
        """
        :param number: 公钥、私钥
        """
        self.pubkey, self.privkey = rsa.newkeys(number)

    def rsaEncrypt(self, text):
        """
        :param test: str
        :return: bytes
        """
        content = text.encode('utf-8')
        crypto = rsa.encrypt(content, self.pubkey)
        return crypto

    def rsaDecrypt(self, text):
        """
        :param text:bytes
        :return: str
        """
        content = rsa.decrypt(text, self.privkey)
        con = content.decode('utf-8')
        return con

    def savePem(self, path_name, text):
        """
        :param path_name: 保存路径
        :param text: str
        :return:bytes
        """
        if "PEM" in path_name.upper():
            path_name = path_name[:-4]
        with open('{}.pem'.format(path_name), 'bw') as f:
            f.write(text.save_pkcs1())

    def readPem(self, path_name, key_type):
        """
        :param path_name: 密钥文件
        :param key_type:类型
        :return:
        """
        if 'pubkey' in key_type:
            self.pubkey = rsa.PublicKey.load_pkcs1(path_name)
        else:
            self.privkey = rsa.PublicKey.load_pkcs1(path_name)
        return True

    def sign(self, message, priv_key=None, hash_method='SHA-1'):
        """
        生成明文的哈希签名以便还原后对照
        :param message: str
        :param priv_key:
        :param hash_method: 哈希的模式
        :return:
        """
        if None == priv_key:
            priv_key = self.privkey
        return rsa.sign(message.encode(), priv_key, hash_method)

    def checkSign(self, mess, result, pubkey=None):
        """
        验证签名:传入解密后明文、签名、公钥,验证成功返回哈希方法,失败则报错
        :param mess: str
        :param result: bytes
        :param pubkey:
        :return: str
        """
        if None == pubkey:
            pubkey = self.privkey
        try:
            result = rsa.verify(mess, result, pubkey)
            return result
        except:
            return False


class USE_DES:
    """
    des(key,[mode], [IV], [pad], [pad mode])
    key:必须正好8字节
    mode(模式):ECB、CBC
    iv:CBC模式中必须提供长8字节
    pad:填充字符
    padmode:加密填充模式PAD_NORMAL or PAD_PKCS5
    """
    def __init__(self, key, iv):
        if not isinstance(key, bytes):
            key = bytes(key, encoding="utf8")
        if not isinstance(iv, bytes):
            iv = bytes(iv, encoding="utf8")
        self.key = key
        self.iv = iv

    def encrypt(self, text):
        """
        DES 加密
        :param text: 原始字符串
        :return: 加密后字符串,bytes
        """
        if not isinstance(text, bytes):
            text = bytes(text, "utf-8")
        secret_key = self.key
        iv = self.iv
        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
        en = k.encrypt(text, padmode=PAD_PKCS5)
        return en

    def descrypt(self, text):
        """
        DES 解密
        :param text: 加密后的字符串,bytes
        :return:  解密后的字符串
        """
        secret_key = self.key
        iv = self.iv
        k = des(secret_key, CBC, iv, pad=None, padmode=PAD_PKCS5)
        de = k.decrypt(text, padmode=PAD_PKCS5)
        return de.decode()


class USE_DES3:
    """
    new(key, mode, *args, **kwargs)
    key:必须8bytes倍数介于16-24
    mode:
    iv:初始化向量适用于MODE_CBC、MODE_CFB、MODE_OFB、MODE_OPENPGP,4种模式
        ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB``长度为8bytes
        ```MODE_OPENPGP```加密时8bytes解密时10bytes
        未提供默认随机生成
    nonce:仅在 ``MODE_EAX`` and ``MODE_CTR``模式中使用
            ``MODE_EAX``建议16bytes
            ``MODE_CTR``建议[0, 7]长度
            未提供则随机生成
    segment_size:分段大小,仅在 ``MODE_CFB``模式中使用,长度为8倍数,未指定则默认为8
    mac_len:适用``MODE_EAX``模式,身份验证标记的长度(字节),它不能超过8(默认值)
    initial_value:适用```MODE_CTR```,计数器的初始值计数器块。默认为**0**。
    """
    def __init__(self, key):
        self.key = key
        self.mode = DES3.MODE_ECB

    def encrypt(self, text):
        """
        传入明文
        :param text:bytes类型,长度是KEY的倍数
        :return:
        """
        if not isinstance(text, bytes):
            text = bytes(text, 'utf-8')
        x = len(text) % 8
        text = text b''*x
        cryptor = DES3.new(self.key, self.mode)
        ciphertext = cryptor.encrypt(text)
        return ciphertext

    def decrypt(self, text):
        cryptor = DES3.new(self.key, self.mode)
        plain_text = cryptor.decrypt(text)
        st = str(plain_text.decode("utf-8")).rstrip('')
        return st


def USE_MD5(test):
    if not isinstance(test, bytes):
        test = bytes(test, 'utf-8')
    m = hashlib.md5()
    m.update(test)
    return m.hexdigest()


def USE_HMAC(key, text):
    if not isinstance(key, bytes):
        key = bytes(key, 'utf-8')
    if not isinstance(text, bytes):
        text = bytes(text, 'utf-8')
    h = hmac.new(key, text, digestmod='MD5')
    return h.hexdigest()


def USE_SHA(text):
    if not isinstance(text, bytes):
        text = bytes(text, 'utf-8')
    sha = hashlib.sha1(text)
    encrypts = sha.hexdigest()
    return encrypts


if __name__ == '__main__':
    aes_test = USE_AES("assssssssdfasasasasa")
    a = aes_test.encrypt("测试")
    b = aes_test.decodebytes(a)
    rsa_test = USE_RSA()
    a = rsa_test.rsaEncrypt("测试加密")
    b = rsa_test.rsaDecrypt(a)
    des_test = USE_DES(b"12345678", b"12345678")
    a = des_test.encrypt("测试加密")
    b = des_test.descrypt(a)
    des3_test = USE_DES3(b"123456789qazxswe")
    a = des3_test.encrypt("测试加密")
    b = des3_test.decrypt(a)
    md5_test = USE_MD5("测试签名")
    hmac_test = USE_HMAC("123456", "测试")
    sha_test = USE_SHA("测试加密")

0 人点赞