工大助手电费查询接口讲解
本人是工大的一名学生,平时没事就喜欢写写代码,今天我来教大家解析学校电费查询接口中的参数,首先打开工大助手的web端https://huthelper.cn/,先登录,进入电费查询栏,进去network发现接口地址https://api.huthelper.cn/api/v3/get/power_e/1/30/412/1740*******9/8c53c79c80********95423461a83d299cac3706/1dcf5b3dab025ddeffcbab3e49dfb5c7198a92c9
只有最后一部分1dcf5b3dab025ddeffcbab3e49dfb5c7198a92c9是关键的,中间部分是写死的,所以我们要做的就是拿到最后这一部分的参数,下面我们一起来解析这个接口:
在浏览器中右键检查,选中查询按钮可以找到这个按钮的点击事件
但是点进去之后发现所有的js全部是压缩的,这样就没法打断点了,所以我们接触fildder这个工具将部分js文件替换为本地的文件,我们只要将本地的js代码进行格式化就行了,经过多次断点调试找到关键性代码在这里
先是进入第一个函数,参数
e=304121740********98c53c79c80d6d5a27995423461a83d299cac37061
经过对参数的分析发现参数的构成是
宿舍楼号码+宿舍门牌号+学号+(固定值)8c53c79c8************61a83d299cac3706+校区代码(0或者1)
在第一个函数的最开始调用了第二个函数,从函数名就不难发现这个函数是将传进来的字符串变成字节数组,现在我们用java来模拟这个过程
//获取第一步处理后的数组
public static long[] oneStep(String str){byte[] e = str.getBytes() ;int[] n = byteToWords(e) ;int o = 8*e.length ;int[] i = new int[80] ;long s = 1732584193 ;long c = - 271733879 ;long u = -1732584194 ;long l = 271733878 ;long f = -1009589776 ;n[o >> 5] |= 128 << 24 - o % 32 ;n[15 + (o + 64 >>> 9 << 4)] = o ;for (int p = 0; p < n.length; p += 16) {long m = s, h = c, d = u, y = l, v = f;for (int b = 0; b < 80; b++) {if (b < 16)i[b] = n[p + b];else {long g = (int)(i[b - 3] ^ i[b - 8] ^ i[b - 14] ^ i[b - 16]);i[b] = (g <= Integer.MAX_VALUE ? (int)g << 1 : (int)(g << 1)) | (g <= Integer.MAX_VALUE ? (int)g >>> 31 : (int)(g >>> 31)) ;}long a1 = s <= Integer.MAX_VALUE ? (int)s << 5 : (int) (s << 5) ; long a2 = i[b] & 0x0FFFFFFFFl; long a6 = s <= Integer.MAX_VALUE ? (int)s >>> 27 : (int)((s & 0x0FFFFFFFFl ) >> 27) ;long a3 = (int)(c & u | ~c & l) ;long a4 = (int)(c ^ u ^ l) ;long a5 = (int)(c & u | c & l | u & l) ;long w = (a1 | a6) + f + a2 + (b < 20 ? 1518500249l + a3 : b < 40 ? 1859775393l + a4 : b < 60 ? a5 - 1894007588l : a4 - 899497514l);f = l;l = u;u = c <= Integer.MAX_VALUE ? ((int)c << 30) | ((int)c >>> 2) : (int)(c << 30 | (c & 0x0FFFFFFFFl) >>> 2) ;c = s ;s = w <= Integer.MAX_VALUE ? (int)w : w ;}s += m;c += h;u += d;l += y;f += v ;}return new long[]{s , c , u , l , f} ;
}
因为在js中的数据类型和java有比较大的区别,经过断点调试发现里面有很多次数据大小超过了int型,所以我在java中使用长整形long来模拟,然后就是 >>> 这个运算符java中运行结果和js有区别,通过查资料发现 >>> 和 >> 的区别是 >>>会先将数据转换为无符号类型,所以我们在java中使用 >> 来模拟js中的 >>> ,先将数据和0x0FFFFFFFFl做与运算,再将数据进行移位就可以和js运行结果一致了,但是这个函数返回的也是一个数组,而我们要的是类似于1dcf5b3dab025ddeffcbab3e49dfb5c7198a92c9这样的字符串,
所以我们找运行完这个方法又跳到哪个方法中去了,通过一些断点找到了之后跳到那个方法了
通过调试发现浏览器依次执行了这三个方法,我们用java来模拟这三个方法,
public static int[] byteToWords(byte[] e){int[] t = new int[32] ;for(int n=0 ,r=0 ; n<e.length ; n++ , r+=8){t[r >>> 5] |= e[n] << 24 - r%32 ;}return t ;
}public static List<Long> wordsToBytes(long[] e){List<Long> t = new ArrayList<Long>() ; for (int n = 0; n < 32 * e.length; n += 8)t.add(e[n >>> 5] >>> 24 - n % 32 & 255);return t ;
}public static String bytesToHex(List<Long> e){StringBuffer buff = new StringBuffer() ;for (Long l : e) {buff.append(Integer.toHexString((int) (l >>> 4)));buff.append(Integer.toHexString((int) (15 & l))) ;}return buff.toString() ;
}
好的然后写一个方法调用这些方法来生成一个可用的访问地址,
/*** * @param a 宿舍楼号* @param b 宿舍门牌号* @param c 学生学号* @param d 校区* @return*/
public static String getUrl(String a , String b , String c , Integer d){if(d != 1 && d != 2){throw new RuntimeException("校区不存在") ;}String str = a+b+c+"8c53c79c80d6d5a27995423461a83d299cac3706"+d ;long[] data = oneStep(str) ;List<Long> list = wordsToBytes(data) ;String key = bytesToHex(list);String url = "https://api.huthelper.cn/api/v3/get/power_e/"+d+"/"+a+"/"+b+"/"+c+"/8c53c79**************423461a83d299cac3706/"+key ;return url ;
}
在main方法中调试一下,将a写成学校任意楼号,b写该楼号的宿舍门牌号,c写一个学生学号,d写校区代码,所以在main方法中这样调用一下就行了
public static void main(String[] args) throws IOException {String path = getUrl("31", "410", "1740************9", 2);System.out.println(path) ;
}
程序允熙那个结果:
https://api.huthelper.cn/api/v3/get/power_e/2/31/413/1740**********9/8c5*******************461a83d299cac3706/f71326845b45b0c45c42371bdf139ac1aeb916f5
这个地址在任意浏览器都可以访问,代码全部在上面了自己整理一下就能用了