【爬虫逆向分析实战】某笔登录算法分析——本地替换分析法
作者:mmseoamin日期:2023-12-11

前言

作者最近在做一个收集粉币的项目,可以用来干嘛这里就不展开了😁,需要进行登录换算token从而达到监控收集的作用,手机抓包发现他是通过APP进行计算之后再请求接口的,通过官网分析可能要比APP逆向方便多,但是通过这几天的观察我并没有头绪,这篇文章草稿创建了接近一个月了,无从下笔,借助了人工智能也没有达到效果,可见它的难度不一般(也可能是我JS基础太过薄弱的原因),本次我们用一种分析方法慢慢的瓦解击破他的层层逻辑!

JS启动分析

这里从网站入手,原因如下:

  • 没有验证码
  • JS结构清晰

    在这里插入图片描述

    观察不难发现,密码是被加密的

    在这里插入图片描述

    必定是通过js进行加密的,我们查看启动器

    在这里插入图片描述

    发现有以下几个关键JS

    在这里插入图片描述

    第一感觉是,main为主方法,其他的是用来调用的,encrypt应该是用于加密的方法,通过上面的启动器证实了main.js的确是优先启动的

    找到main.js搜索password

    密码通过this.encrypt()进行加密的

    在这里插入图片描述

    var n = {
    phone: this.phone,
    verification: this.verification,
    password: this.encrypt(this.password)
    };
    

    找到encrypt()方法

    encrypt(n) {
    return window.encrypt(this.publicKey, n)
    }
    

    需要用到一个参数publicKey

    在这里插入图片描述

    到这里我们基本搞清楚了,登录时将原密码,进行调用window.encrypt(this.publicKey, n)加密

    猜想

    猜测n为原密码,如何证实呢?有很多人想说观察代码的调用,这当然可以,但如果是复杂的代码或者加密的你还能看吗?

    这里用了一个浏览器自带的功能本地替换,可以无视代码加密,为什么这么说,因为代码加密最后还是要被执行,不能执行的代码加密了有啥用呢??

    我们找到main.js将n弹窗显示

         encrypt(n) {
          alert(n);
          return encrypt(this.publicKey, n)
          }
    

    在这里插入图片描述

    替换到本地启用后,我们进行登录模拟,看看有没有效果?

    在这里插入图片描述

    在这里插入图片描述

    这里将我的登录密码弹出来了,猜想正确!

    顺藤摸瓜

    有了刚刚的思想,我们直接找encrypt.js,因为在main.js中最后调用了

     return encrypt(this.publicKey, n)
    

    而在main.js中没有其他方法了 ,在encrypt.js我们找到了相关方法

     av.encrypt = function(aG, z) {
     
            var t = new N();
            t.setPublic(a(aG), "10001");
            
            return ai(t.encrypt(z))
        }
    

    代码是否运行到这里,和刚刚一样验证一下就可以了

    在这里插入图片描述

    发现又调用了新的方法ai(t.encrypt(z))

     function ai(aG) {
            var z;
            var aH;
            var t = "";
            for (z = 0; z + 3 <= aG.length; z += 3) {
                aH = parseInt(aG.substring(z, z + 3), 16);
                t += ad.charAt(aH >> 6) + ad.charAt(aH & 63)
            }
            if (z + 1 == aG.length) {
                aH = parseInt(aG.substring(z, z + 1), 16);
                t += ad.charAt(aH << 2)
            } else {
                if (z + 2 == aG.length) {
                    aH = parseInt(aG.substring(z, z + 2), 16);
                    t += ad.charAt(aH >> 2) + ad.charAt((aH & 3) << 4)
                }
            }
            while ((t.length & 3) > 0) {
                t += Y
            }
            alert(t);
            return t
            
        }
    

    我们在修改代码将t进行弹窗显示,重新来一遍整个登录过程,观察最后的加密密码是否与请求的一致

    模拟登录测试

    在这里插入图片描述

    在这里插入图片描述

    经过对比是一致的,由于我们的环境是python,接下来借助GPT进行代码转换

    代码转换

    通过将涉及到的函数调用方法进行罗列,通过人工智能改写

    var publicKey='ANKi9PWuvDOsagwIVvrPx77mXNV0APmjySsYjB1/GtUTY6cyKNRl2RCTt608m9nYk5VeCG2EAZRQmQNQTyfZkw0Uo+MytAkjj17BXOpY4o6+BToi7rRKfTGl6J60/XBZcGSzN1XVZ80ElSjaGE8Ocg8wbPN18tbmsy761zN5S';
    var n='密码'
    encrypt(publicKey, n)
    encrypt(aG, z) {
            var t = new N();
            t.setPublic(a(aG), "10001");
            return ai(t.encrypt(z))
        }
        function a(aI) {
            alert("经过");
            var aG = "";
            var aH;
            var t = 0;
            var z;
            for (aH = 0; aH < aI.length; ++aH) {
                if (aI.charAt(aH) == Y) {
                    break
                }
                v = ad.indexOf(aI.charAt(aH));
                if (v < 0) {
                    continue
                }
                if (t == 0) {
                    aG += aF(v >> 2);
                    z = v & 3;
                    t = 1
                } else {
                    if (t == 1) {
                        aG += aF((z << 2) | (v >> 4));
                        z = v & 15;
                        t = 2
                    } else {
                        if (t == 2) {
                            aG += aF(z);
                            aG += aF(v >> 2);
                            z = v & 3;
                            t = 3
                        } else {
                            aG += aF((z << 2) | (v >> 4));
                            aG += aF(v & 15);
                            t = 0
                        }
                    }
                }
            }
            if (t == 1) {
                aG += aF(z << 2)
            }
            return aG
        }
            function ai(aG) {
            // alert(aG);
            var z;
            var aH;
            var t = "";
            for (z = 0; z + 3 <= aG.length; z += 3) {
                aH = parseInt(aG.substring(z, z + 3), 16);
                t += ad.charAt(aH >> 6) + ad.charAt(aH & 63)
            }
            if (z + 1 == aG.length) {
                aH = parseInt(aG.substring(z, z + 1), 16);
                t += ad.charAt(aH << 2)
            } else {
                if (z + 2 == aG.length) {
                    aH = parseInt(aG.substring(z, z + 2), 16);
                    t += ad.charAt(aH >> 2) + ad.charAt((aH & 3) << 4)
                }
            }
            while ((t.length & 3) > 0) {
                t += Y
            }
            alert(t);
            return t
            
        }