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

i茅台自动申购算法协议分析

首发地址:http://zhuoyue360.com/crack/104.html

一、引言

今日看到有人分享了i茅台自动申购的文章。但是它酷似引流文章,全文一张图,呜呜呜。无法白嫖。太可恶了,因此,我来啦~ 我来整一整,我也要抢茅子!

二、开战

开发者详情:贵州茅台酒销售有限公司

版本信息:1.4.5

更新时间:2023/07/25 19:07

(一) 启动闪退

由于我们的环境特别的异常 Root,Xposed,Fridd,抓包的啥都有。

管他啥检测,先上个Shamiko配置排除列表. 就可以正常打开了~

img

(二) 抓包分析

本次使用的抓包手段是 Postern + Charles的抓包方案。

当我们点击登录以后,应用提示未检测到网络信号。它一定是有抓包检测的。

img

作为资深的脚本小子,我们再次借用大佬们做好的工具JustMePlus,提示验证码过期,我们也抓到了包数据。

img

看一下提交的数据。有几个不知道含义的字段MT-V、MT-Device-ID、MT-Request-ID、MT-R、MT-SN和BS-DVID参数。找到了未知的参数,我们的目标也就明确了。

POST /xhr/front/user/register/login HTTP/1.1
MT-K: 1690425040309
MT-V: 33212ce8f99d64231e221a5ec9y
MT-Token: 
User-Agent: android;29;google;sailfish
MT-Device-ID: clips_Kxx/RnJBdEYlFyZEJRx6QycQI0V2FydBcxd0FXZH
MT-APP-Version: 1.4.5
MT-Request-ID: 3b2b66c3-747d-4ce7-ba28-a3066594247e
MT-Network-Type: WIFI
MT-R: clips_OlU6TmFRag5rCXwbNAQ/Tz1SKlN8THcecBp/HGhHdw==
MT-Bundle-ID: com.moutai.mall
MT-USER-TAG: 0
MT-SN: clips_ehwpSC0fLBggRnJAdxYgFiAYLxl9Si5PfEl/TC0afkw=
MT-DTIME: Wed Aug 14 09:25:50 GMT+08:00 2019
MT-RS: 1080*1794
MT-Lng: 
MT-Lat: 
BS-DVID: tDkAoOWWVDbDFNobZRf1eMcF364bZwAjmM87iuSKpikmnWOBRbaGo1ZQOYt0lu5NQDNwm1S-hrcW4Falp_9YIdg
MT-DOUBLE: 0
MT-SIM: 0
MT-ACBE: 0
MT-ACB: 0
MT-ACBM: 0
Content-Type: application/json; charset=UTF-8
Content-Length: 67
Host: app.moutai519.com.cn
Connection: Keep-Alive
Accept-Encoding: gzip{"vCode":"111111","mobile":"13544711111","ydToken":"","ydLogId":""}

(三) 脱壳

看到libbaiduprotect.so文件,它使用了百度加固。接下来,脚本小子继续上!我使用的是FunDex

img

(四) 分析

使用的是Frida16大版本.

1. MT-K、MT-V (非必须)

随便跟踪一下。

img

img

Pair<String, String> b10 = new RandK().b(n.n("", qm.b.e(System.currentTimeMillis())), wf.a.c(), "");

一、qm.b.e(System.currentTimeMillis())

它其实就等于 new Long(System.currentTimeMillis())

public final class b {public static final Boolean a(boolean z10) {return Boolean.valueOf(z10);}public static final Double b(double d10) {return new Double(d10);}public static final Float c(float f10) {return new Float(f10);}public static final Integer d(int i10) {return new Integer(i10);}public static final Long e(long j10) {return new Long(j10);}
}

二、wf.a.c()

这里我把关键的函数给提取出来,先从部分一开始分析。因为它已经涉及到SO了。脚本小子继续上,这里使用yang神的HookRegisterNative的脚本。

//   部分一
public static final String DEVICE_ID = "device_id";static {EnumMap<MMKVRecoverStrategic, Integer> enumMap = new EnumMap<>(MMKVRecoverStrategic.class);recoverIndex = enumMap;enumMap.put((EnumMap<MMKVRecoverStrategic, Integer>) MMKVRecoverStrategic.OnErrorDiscard, (MMKVRecoverStrategic) 0);recoverIndex.put((EnumMap<MMKVRecoverStrategic, Integer>) MMKVRecoverStrategic.OnErrorRecover, (MMKVRecoverStrategic) 1);System.loadLibrary("c++_shared");System.loadLibrary("mmkv");rootDir = null;mCreators = new HashMap<>();
}private MMKV(long j10) {this.nativeHandle = j10;
}private static native long getMMKVWithID(String str, int i10, String str2);public static MMKV mmkvWithID(String str, int i10) {if (rootDir != null) {return new MMKV(getMMKVWithID(str, i10, null));}throw new IllegalStateException("You should Call MMKV.initialize() first.");
}public static MMKV d(Context context, String str, boolean z10) {if (TextUtils.isEmpty(str)) {return null;}MMKV mmkv = a.get(str);if (mmkv == null && z10) {MMKV mmkvWithID = MMKV.mmkvWithID(str, 2);a.put(str, mmkvWithID);return mmkvWithID;}return mmkv;
}public static String e(Context context, String str, String str2, String str3) {MMKV d10 = d(context, str, true);return d10 != null ? d10.getString(str2, str3) : str3;
}public static Application a() {if (a == null) {a = a.e();}return a;
}public static String k(String str, String str2, String str3) {return sj.a.e(b.a(), str, str2, str3);
}public static String e(String str, String str2) {return k("YanXuan", str, str2);
}public static String j() {return jk.a.e(PushConstants.DEVICE_ID, null);
}public static synchronized String c() {synchronized (a.class) {if (TextUtils.isEmpty(a)) {String j10 = j();a = j10;if (!TextUtils.isEmpty(j10)) {return a;}String a10 = a();a = a10;p(a10);}return a;}}

开始Hook看看函数的注册地址,再去用IDA分析,必须要偷懒~

frida -U -f com.moutai.mall -l .\hook_registerNative.js

很遗憾,但是又是在意料之中的事,应用存在Frida检测。看着日志信息,该反调试应该是由百度加固提供的.所以去看看它的so

[RegisterNatives] java_class: com.example.vmp.Hook.LHook name: getDexSizeForDexFile sig: (Ljava/lang/Object;)[I fnPtr: 0x72955fa5b0  fnOffset: 0x72955fa5b0 libLVmp.so!0x355b0  callee: 0x72955fb694 libLVmp.so!0x36694
[RegisterNatives] method_count: 0x1
[RegisterNatives] java_class: com.sagittarius.v6.D name: n0 sig: (I)I fnPtr: 0x728aecec64  fnOffset: 0x728aecec64 libbaiduprotect.so!0x32c64  callee: 0x728aeceae4 libbaiduprotect.so!0x32ae4
[RegisterNatives] method_count: 0x3
[RegisterNatives] java_class: com.sagittarius.v6.A name: n1 sig: (Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V fnPtr: 0x728aeb00f4  fnOffset: 0x728aeb00f4 libbaiduprotect.so!0x140f4 callee: 0x728aeb0090 libbaiduprotect.so!0x14090
[RegisterNatives] java_class: com.sagittarius.v6.A name: n2 sig: (Landroid/content/Context;)V fnPtr: 0x728aeb02b4  fnOffset: 0x728aeb02b4 libbaiduprotect.so!0x142b4  callee: 0x728aeb0090 libbaiduprotect.so!0x14090
[RegisterNatives] java_class: com.sagittarius.v6.A name: n3 sig: (Landroid/content/Context;)V fnPtr: 0x728aeb039c  fnOffset: 0x728aeb039c libbaiduprotect.so!0x1439c  callee: 0x728aeb0090 libbaiduprotect.so!0x14090
Process crashed: Bad access due to protection failure***
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sailfish/sailfish:10/QP1A.190711.020/5800535:user/release-keys'
Revision: '0'
ABI: 'arm64'
Timestamp: 2023-07-27 10:58:52+0800
pid: 19932, tid: 19974, name: com.moutai.mall  >>> com.moutai.mall <<<
uid: 10234
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x73883f4b20
Abort message: 'state=545'x0  0000007388402a68  x1  0000000000001000  x2  0000000000000001  x3  0000000000000000x4  00000072f11f4120  x5  00000072f11f4140  x6  0000007388548280  x7  00000073885482c0x8  0000000000000000  x9  0000000000000002  x10 0000000000000001  x11 0000000000000000x12 0000007388548240  x13 0000007388548200  x14 0000000000000000  x15 00000072f11acd40x16 0000007386ac6888  x17 0000007386ab969c  x18 0000000000000077  x19 0000000000000000x20 000000000000000c  x21 000000738994f000  x22 0000000000001000  x23 0000007386ac82e0x24 0000007388402a68  x25 00000073883f4b20  x26 000000738994f118  x27 0000007386ac8000x28 0000000000000018  x29 0000007289bea7b0sp  0000007289bea750  lr  0000007386abb5a8  pc  00000073883f4b20backtrace:#00 pc 0000000000001b20  [anon:thread signal stack]#01 pc 00000000000e65a4  /apex/com.android.runtime/lib64/bionic/libc.so!libc.so (offset 0xe6000) (__cxa_finalize+212) (BuildId: 5812256023147338b8a9538321d4c456)#02 pc 00000000000e1ea8  /apex/com.android.runtime/lib64/bionic/libc.so!libc.so (offset 0xe1000) (exit+24) (BuildId: 5812256023147338b8a9538321d4c456)#03 pc 0000000000000008  <anonymous:72fb904000>
***

当我们使用IDA打开以后,发现它非常的苦恼,没法F5,那 我们还咋分析!这回没法借助脚本了。问了个好朋友,好朋友喊我DumpSo,我使用了FunELF工具,这效果也是嗷嗷好!

img

img

还记得以前在霜哥课程里面学的frida反调试,把检测线程直接干掉,这个也嗷嗷好用。在这里反调试我选择了霜哥的方法。

frida -U -f com.moutai.mall -l .\hook_anti-thread.js

干掉线程的脚本

function replace_thread() {var pthread_create_addr = Module.findExportByName(null, "pthread_create");var pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);Interceptor.replace(pthread_create_addr, new NativeCallback((parg0, parg1, parg2, parg3) => {var so_name = Process.findModuleByAddress(parg2).name;var so_base = Module.getBaseAddress(so_name);var offset = (parg2 - so_base);var PC = 0;console.log("normal find thread func offset", so_name, parg2,offset, offset.toString(16));// if ((so_name.indexOf("libmsaoaidsec.so") > -1)) {//     if (offset === 123) {//     } else if (offset === 95736) {//     } else if (offset === 93488) {//     }//     else {//         console.log("normal find thread func offset", so_name, offset, offset.toString(16));//         PC = pthread_create(parg0, parg1, parg2, parg3);//     }// } else {//     PC = pthread_create(parg0, parg1, parg2, parg3);// }if ((so_name.indexOf("libbaiduprotect.so") > -1)) {if (offset === 178752) {} else {console.log("normal find thread func offset", so_name, offset, offset.toString(16));PC = pthread_create(parg0, parg1, parg2, parg3);}} else {PC = pthread_create(parg0, parg1, parg2, parg3);}return PC;}, "int", ["pointer", "pointer", "pointer", "pointer"]));
}setImmediate(replace_thread)

于是乎,我们就把i茅台的反调试给过掉了,虽然不知道怎么检测了啥。脚本小子,不需要知道那么多! 继续RUN,RUN,RUN

我们继续回到wf.a.c

2. MT-Device-ID

let b = Java.use("ic.b");
b["a"].implementation = function (str) {console.log(`b.a is called: str=${str}`);let result = this["a"](str);console.log(`b.a result=${result}`);return result;
};
b.a is called: str=d127e6d9172a92a949532d2b6edd8b4e
b.a result=clips_LB0vGH1LLxYnECJDekgpECQdKBspTX8dK04qTnYUIEU=

再把堆栈打出来,发现d127e6d9172a92a949532d2b6edd8b4e是来自于wf.a.c(),这个方法在MT-V、MT-K中也用到了。这里就不多说了.

public static String j() {return jk.a.e(PushConstants.DEVICE_ID, null);
}public static String a() {String d10 = d();String e10 = e();String i10 = i();String b10 = b();if (!TextUtils.isEmpty(d10) && n(d10) && !TextUtils.isEmpty(e10) && m(e10)) {d10 = d10 + "@" + e10;} else if (!TextUtils.isEmpty(e10) && m(e10)) {d10 = e10;} else if (TextUtils.isEmpty(d10) || !n(d10)) {if (TextUtils.isEmpty(i10) || !o(i10)) {d10 = !TextUtils.isEmpty(b10) ? b10 : "";} else {d10 = i10;}}if (TextUtils.isEmpty(d10)) {try {d10 = UUID.randomUUID().toString();} catch (Exception unused) {}}String a10 = b.a(d10, "UTF-8");return !TextUtils.isEmpty(a10) ? a10.trim() : d10;}public static synchronized String c() {synchronized (a.class) {if (TextUtils.isEmpty(a)) {String j10 = j();a = j10;if (!TextUtils.isEmpty(j10)) {return a;}String a10 = a();a = a10;p(a10);}return a;}
}wf.a.c()
public class a {public static String a(byte[] bArr) {return Base64.encodeToString(bArr, 2);}public static String b(String str) {try {return a(str.getBytes("UTF-8"));} catch (UnsupportedEncodingException e10) {e10.printStackTrace();return null;}}
}public static String a(String str) {  // str = deviceId_md5if (TextUtils.isBlank(str)) {return str;}String b10 = a.b(b(str, 72));return "clips_" + b10;
}public static String b(String str, int i10) {if (TextUtils.isBlank(str)) {return str;}StringBuilder sb2 = new StringBuilder();for (char c10 : str.toCharArray()) {i10 ^= c10;sb2.append((char) i10);}return sb2.toString();
}

总的来说逻辑如下:

  1. deviceID = 获取设备号deviceId
  2. deviceId_md5 = MD5(deviceID)
  3. mt_device_id = base64(xor(deviceId_md5))
import base64
import hashlib
import uuiddef getDeviceId():# UUIDreturn uuid.uuid4()def md5(deviceId):if not str:return Noneif not deviceId:str2 = "UTF-8"try:message_digest = hashlib.md5()message_digest.update(str.encode(deviceId))digest = message_digest.digest()string_buffer = ""for b10 in digest:string_buffer += format(b10, 'x')return string_bufferexcept Exception as e:return None
def getMTDeviceId(deviceId):ret = []i10 = 72for char in deviceId:i10 ^= ord(char)ret.append(chr(i10))ret = ''.join(ret)return base64.b64encode(ret.encode()).decode()if __name__ == '__main__':deviceidMd5 = md5('d38d477f-9804-4667-822f-750d15e10915')mt_device_id = getMTDeviceId(deviceidMd5)print(mt_device_id)

在发送验证码的时候,有一个参数md5。这个就比较简单了。

str = 手机号;
String l10 = j10.l("2af72f100c356273d46284f6fd1dfc08" + str + currentTimeMillis);

然后其他就没什么难得东西了。

{'code': 2000}
验证码:271744
{'code': 2000, 'data': {'userId': 1127142557, 'userName': '用户1127142557', 'mobile': '135****9983', 'verifyStatus': 0, 'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtdCIsImV4cCI6MTY5MzAzNzU4MSwidXNlcklkIjoxMTI3MTQyNTU3LCJkZXZpY2VJZCI6ImNsaXBzX0xCb2pFSE5ISlJZaUczNVBmVVVrRVNaRkp4RW5GbmRESWhCeEZDWVMiLCJpYXQiOjE2OTA0NDU1ODF9.V_hJSKm3D6I56-6u9TkON4ZzFK6vkzey4wo9miSOAb4', 'userTag': 0, 'cookie': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtdCIsImV4cCI6MTY5MzAzNzU4MSwidXNlcklkIjoxMTI3MTQyNTU3LCJkZXZpY2VJZCI6ImNsaXBzX0xCb2pFSE5ISlJZaUczNVBmVVVrRVNaRkp4RW5GbmRESWhCeEZDWVMiLCJpYXQiOjE2OTA0NDU1ODF9.fRFdAM_cVjsTSRtLIP5tl9zHLxs_-sW2L_9wJkHeZQQ'}}

(五) 登录代码

import base64
import hashlib
import time
import uuidimport requestsdef getDeviceId():# UUIDreturn str(uuid.uuid4())def md5(deviceId):if not str:return Noneif not deviceId:str2 = "UTF-8"try:message_digest = hashlib.md5()message_digest.update(str.encode(deviceId))digest = message_digest.digest()string_buffer = ""for b10 in digest:string_buffer += format(b10, 'x')return string_bufferexcept Exception as e:return Nonedef getMTDeviceId(deviceId):ret = []i10 = 72for char in deviceId:i10 ^= ord(char)ret.append(chr(i10))ret = ''.join(ret)return 'clips_' + base64.b64encode(ret.encode()).decode()def sendCode(phone,mt_device_id):timestamp =str(int(time.time() * 1000))url = 'https://app.moutai519.com.cn/xhr/front/user/register/vcode'md5_str = '2af72f100c356273d46284f6fd1dfc08' + phone + timestampmd5_str = hashlib.md5(md5_str.encode()).hexdigest()data = {"md5":md5_str,"mobile":phone,"timestamp":timestamp}headers = {"MT-Token": "","User-Agent": "android;29;google;sailfish","MT-Device-ID": mt_device_id,"MT-APP-Version": "1.4.5","MT-Request-ID": str(uuid.uuid4()),"MT-Network-Type": "WIFI","MT-Bundle-ID": "com.moutai.mall","MT-USER-TAG": "0","MT-RS": "1080*1794","Content-Type": "application/json; charset=UTF-8","Host": "app.moutai519.com.cn"}return requests.post(url=url, json=data, headers=headers).json()def login(phone,code,mt_device_id):url = 'https://app.moutai519.com.cn/xhr/front/user/register/login'data = {"vCode":code,"mobile":phone,"ydToken":"","ydLogId":""}headers = {"MT-Token": "","User-Agent": "android;29;google;sailfish","MT-Device-ID": mt_device_id,"MT-APP-Version": "1.4.5","MT-Request-ID": str(uuid.uuid4()),"MT-Network-Type": "WIFI","MT-Bundle-ID": "com.moutai.mall","MT-USER-TAG": "0","MT-RS": "1080*1794","Content-Type": "application/json; charset=UTF-8","Host": "app.moutai519.com.cn"}return requests.post(url=url, json=data, headers=headers).json()
def go():deviceId = getDeviceId()deviceidMd5 = md5(deviceId)mt_device_id = getMTDeviceId(deviceidMd5)print(mt_device_id)phone = "135********"data = sendCode(phone,mt_device_id)print(data)if data['code'] != 2000:print('异常')returncode = input('验证码:')print(login(phone, code, mt_device_id))
if __name__ == '__main__':go()
请输入手机号:13544779983
{'code': 2000}
验证码:271744
{'code': 2000, 'data': {'userId': 123123, 'userName': '123123', 'mobile': '135********', 'verifyStatus': 0, 'token': '****.****.V_hJSKm3D6I56-****', 'userTag': 0, 'cookie': '***.eyJpc3MiOiJtdCIsImV**.*-*'}}

(六) 申购分析(actParam)

在申购得时候,发现一个关键参数也要搞.

{"sessionId": 700,"shopId": "144440300003","itemInfoList": [{"itemId": "10213","count": 1}],"actParam": "oUxr9vtC5s6wgqbkfHZkFAudq+iTYalbyD2cl2/oYIq44OE879P2dJcuXYNHvwht79rANbLKxdxL\n3hg7WmB2upL/xILVsuZ5TMg1A3Lma5dcdficheXbgZc2QmuIs0kJcVaseBdhtrvFiMrfEHCO0g==\n"
}

此处应该上RPC.

img

(七) 其他包

实名包

POST /xhr/front/user/realNameAuth HTTP/1.1
MT-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtdCIsImV4cCI6MTY5MzAzNzcyNCwidXNlcklkIjoxMTI3MTQyNTU3LCJkZXZpY2VJZCI6ImNsaXBzX0xCc3RUSGdlZTBvdlRpeE5LUjBzVFM4YUtSOTdHSDVKY0VRaVFIRkMiLCJpYXQiOjE2OTA0NDU3MjR9.NvaXbgWMOUEqtkyq15zDP8SQqKaGnQxUgoYMdl_aQkk
User-Agent: android;29;google;sailfish
MT-Device-ID: clips_LBstTHgee0ovTixNKR0sTS8aKR97GH5JcEQiQHFC
MT-APP-Version: 1.4.5
MT-Request-ID: e24eb535-daa3-45fd-a7f4-9f5e833d559d
MT-Network-Type: WIFI
MT-R: clips_OlU6TmFRag5rCXwbNAQ/Tz1SKlN8THcecBp/HGhHdw==
MT-Bundle-ID: com.moutai.mall
MT-USER-TAG: 0
MT-SN: clips_ehwpSC0fLBggRnJAdxYgFiAYLxl9Si5PfEl/TC0afkw=
MT-DTIME: Wed Aug 14 09:25:50 GMT+08:00 2019
MT-RS: 1080*1794
MT-Lng: 
MT-Lat: 
BS-DVID: hWr62Q591-OLfaOq1ge1xkVW4OZfwq8jzbHpK2tx-B0Mhg0ZB8SVmhl0MzjFvXjHo7cnRUKQz5p9ChG1rFMxykw
MT-DOUBLE: 0
MT-SIM: 0
MT-ACBE: 0
MT-ACB: 0
MT-ACBM: 0
Content-Type: application/json; charset=UTF-8
Content-Length: 65
Host: app.moutai519.com.cn
Connection: Keep-Alive
Accept-Encoding: gzip{"cardType":0,"idCardName":"ddd","idCardNo":"440582199811054333"}
curl -H "MT-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJtdCIsImV4cCI6MTY5MzAzNzcyNCwidXNlcklkIjoxMTI3MTQyNTU3LCJkZXZpY2VJZCI6ImNsaXBzX0xCc3RUSGdlZTBvdlRpeE5LUjBzVFM4YUtSOTdHSDVKY0VRaVFIRkMiLCJpYXQiOjE2OTA0NDU3MjR9.NvaXbgWMOUEqtkyq15zDP8SQqKaGnQxUgoYMdl_aQkk" -H "User-Agent: android;29;google;sailfish" -H "MT-Device-ID: clips_LBstTHgee0ovTixNKR0sTS8aKR97GH5JcEQiQHFC" -H "MT-APP-Version: 1.4.5" -H "MT-Request-ID: e24eb535-daa3-45fd-a7f4-9f5e833d559d" -H "MT-Network-Type: WIFI" -H "MT-R: clips_OlU6TmFRag5rCXwbNAQ/Tz1SKlN8THcecBp/HGhHdw==" -H "MT-Bundle-ID: com.moutai.mall" -H "MT-USER-TAG: 0" -H "MT-SN: clips_ehwpSC0fLBggRnJAdxYgFiAYLxl9Si5PfEl/TC0afkw=" -H "MT-DTIME: Wed Aug 14 09:25:50 GMT+08:00 2019" -H "MT-RS: 1080*1794" -H "MT-Lng: " -H "MT-Lat: " -H "BS-DVID: hWr62Q591-OLfaOq1ge1xkVW4OZfwq8jzbHpK2tx-B0Mhg0ZB8SVmhl0MzjFvXjHo7cnRUKQz5p9ChG1rFMxykw" -H "MT-DOUBLE: 0" -H "MT-SIM: 0" -H "MT-ACBE: 0" -H "MT-ACB: 0" -H "MT-ACBM: 0" -H "Content-Type: application/json; charset=UTF-8" -H "Host: app.moutai519.com.cn" --data-binary "{\"cardType\":0,\"idCardName\":\"ddd\",\"idCardNo\":\"440582199811054333\"}" --compressed "https://app.moutai519.com.cn/xhr/front/user/realNameAuth"

相关文章:

i茅台自动申购算法协议分析

首发地址:http://zhuoyue360.com/crack/104.html 一、引言 今日看到有人分享了i茅台自动申购的文章。但是它酷似引流文章&#xff0c;全文一张图&#xff0c;呜呜呜。无法白嫖。太可恶了&#xff0c;因此&#xff0c;我来啦~ 我来整一整&#xff0c;我也要抢茅子&#xff01; …...

【HarmonyOS】Java如何引用外部jar包

【关键字】 Java、引用jar包​ 【写在前面】 使用API6和API7开发HarmonyOS应用时&#xff0c;因为应用中只能引用SDK中开放的功能接口&#xff0c;但是部分jdk自带的接口功能在SDK中并未封装&#xff0c;要想在工程中使用jdk开放的接口功能&#xff0c;需要将jdk中的jar包通过…...

vue在线编辑表格导入导出

npm i file-saver npm i exceljs npm i luckyexcelindex.html &#xff08;方式一在html中引入&#xff09; <link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/luckysheetlatest/dist/plugins/css/pluginsCss.css /><link relstylesheet hrefhttps://cdn.jsde…...

监控Kafka的关键指标

Kafka 架构 上面绿色部分 PRODUCER&#xff08;生产者&#xff09;和下面紫色部分 CONSUMER&#xff08;消费者&#xff09;是业务程序&#xff0c;通常由研发人员埋点解决监控问题&#xff0c;如果是 Java 客户端也会暴露 JMX 指标。组件运维监控层面着重关注蓝色部分的 BROKE…...

React18 hook学习笔记

useState useState用于在函数组件中声明和管理状态 它接受初始状态&#xff0c;并返回一个状态变量和一个更新状态的函数 通过调用更新状态的函数&#xff0c;可以改变状态的值并触发组件的重新渲染 import { useState } from "react"function App() {const [obj, …...

Java038——正则表达式

一、认识正则表达式 正则表达式通常被用于判断语句中&#xff0c;用来检查某一字符串是否满足某一格式。正则表达式是含有一些具有特殊意义字符的字符串&#xff0c;这些特殊字符称为正则表达式的元字符。例如&#xff0c;“\d”表示数字 0~9 中的任何一个&#xff0c;“d”就…...

JavaScript元素选择器

目录 一、getElementsByTagName1.说明2.用法示例 二、getElementsByName1.说明2.用法示例 三、getElementById1.说明2.用法示例 四、getElementsByClassName1.说明2.用法示例 五、querySelector1.说明2.用法示例 六、querySelectorAll1.说明2.用法示例 七、综合示例 一、getEle…...

Docker安装 elasticsearch-head

目录 前言安装elasticsearch-head步骤1&#xff1a;准备1. 安装docker2. 搜索可以使用的镜像。3. 也可从docker hub上搜索镜像。4. 选择合适的redis镜像。 步骤2&#xff1a;拉取elasticsearch-head镜像拉取镜像查看已拉取的镜像 步骤3&#xff1a;创建容器创建容器方式1&#…...

交换排序——选择排序和冒泡排序的区别是什么?

今天重温一下算法&#xff0c;其实刚开始我觉得冒泡排序和选择排序是一样的&#xff0c;因为他们排序过程中都是通过相邻的数据比较找到最小/最大的数据&#xff0c;通过不断思考和学习才明白&#xff0c;两者还是有区别的。 冒泡排序 概念 冒泡排序(Bubble Sort)&#xff0…...

吉他谱:Melodies of Life - Final Fantasy Solo Guitar Collections

原始出处&#xff1a; Final Fantasy Solo Guitar Collections - 南泽大介改编的最终幻想9主题曲吉他谱 更多吉他谱&#xff1a; https://github.com/NaisuXu/Guitar_Sheet_Music_Collection...

微信小程序下拉刷新

小程序中的下拉刷新 - 掘金...

TX2 NX 修改设备树--GPIO

确认模组内使用的是哪个设备树文件 模组上电输入如下指令,查看返回值:cat /proc/device-tree/nvidia,dtsfilename找到相应的设备树文件设备树存放路径 /public_sources/Linux_for_Tegra/source/public/kernel_src/hardware/nvidia/platform/t18x/lanai/kernel-dts 确认设备树…...

.NET对象的内存布局

在.NET中&#xff0c;理解对象的内存布局是非常重要的&#xff0c;这将帮助我们更好地理解.NET的运行机制和优化代码&#xff0c;本文将介绍.NET中的对象内存布局。 .NET中的数据类型主要分为两类&#xff0c;值类型和引用类型。值类型包括了基本类型(如int、bool、double、cha…...

Hybrid App 可以从哪些技术路径实现性能优化

说到 Hybrid App&#xff08;混合应用&#xff09;大家都不陌生&#xff0c;因为这种开发模式大行其道发展的这些年取代了很多原生和 Web 应用&#xff0c;为什么大家对这种「Native HTML5」的开发模式额外偏爱呢&#xff1f; 因为一方面在一定程度上兼顾了原生应用的优质体验…...

C++入门篇7---string类

所谓的string类&#xff0c;其实就是我们所说的字符串&#xff0c;本质和c语言中的字符串数组一样&#xff0c;但是为了更符合C面向对象的特性&#xff0c;特地将它写成了一个单独的类&#xff0c;方便我们的使用 对其定义有兴趣的可以去看string类的文档介绍&#xff0c;这里…...

2308d的静态构造函数循环依赖示例

原文 //Steve: __gshared string[string] dict; shared static this() {dict ["a" : "b"]; }这里有两个论点:这不能是CRT构造器,因为它依赖于D运行时,并且认为它应该进入自己的模块是一个QoL问题,当你想要私有到类而不是私有到模块时,可为类提供它,因为语…...

Linux 目录和文件常见操作

就常见的命令&#xff1a; pwd pwd 显示当前的目录 目录迁移 我以如下的目录大致结构做一个简单的例子 cd 迁移到指定的路径&#xff0c;可以指定相对路径和绝对路径&#xff0c;默认相对 .指向当前路径&#xff0c;…/ 指向上一级的目录。 ls 列出文件及其目录 命令选…...

不基于比较的排序:基数排序

本篇只是讨论桶排序的具体实现&#xff0c;想了解更多算法内容可以在我的博客里搜&#xff0c;建议大家看看这篇排序算法总结&#xff1a;排序算法总结_鱼跃鹰飞的博客-CSDN博客 桶排序的原理&#xff1a; 代码&#xff1a;sort1是一个比较二逼的实现方式浪费空间&#xff0c;s…...

shell和反弹shell

文章目录 是什么&#xff1f;bash是什么&#xff1f;反弹shell 是什么&#xff1f; Shell 是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。 Shell 是指一种应用程序&#xff0c;这个应用程序提供了…...

构建Docker容器监控系统(Cadvisor +Prometheus+Grafana)

Cadvisor PrometheusGrafana 1.1、Cadvisor产品简介 Cadvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行Cadvisor用户可以轻松的获取到当前主机上容器的运行统计信息&#xff0c;并以图表的形式向用户展示。 1.2、安装docker-ce [rootloc…...

代码提交即“秒拒”?揭秘如何自动化检测与系统性提升代码质量

在软件开发的快车道上&#xff0c;我们常常面临一个灵魂拷问&#xff1a;“代码能跑&#xff0c;和代码质量好&#xff0c;之间差了几个重构&#xff1f;”很多团队初期靠“人治”——技术负责人手动 Review 核心代码&#xff1b;中期靠“嘴治”——开会强调要写好注释、要遵守…...

告别网络延迟焦虑:手把手教你用gPTP搞定车载TSN网络的微秒级时间同步

车载TSN网络微秒级同步实战&#xff1a;gPTP协议在AUTOSAR平台的深度解析 当一辆L3级自动驾驶汽车以60公里时速行驶时&#xff0c;1毫秒的时间误差意味着车辆位置偏差达到16.7毫米——这个距离足以让毫米波雷达误判前方障碍物的实际位置。这正是车载TSN&#xff08;时间敏感网络…...

从模型仓库到MLOps流水线:我是如何用ModelScope Library搭建个人AI工作台的

从模型仓库到MLOps流水线&#xff1a;我是如何用ModelScope Library搭建个人AI工作台的 第一次接触ModelScope时&#xff0c;我正为一个图像生成项目的模型管理问题头疼不已。团队里每个人都在用不同版本的Stable Diffusion&#xff0c;微调参数和数据集散落在各自的笔记本上&a…...

采用深度学习方法进行图像缺陷检测_使用ResNet50预训练模型来对 太阳能电池板缺陷数据集 12类的缺陷类型进行检测

采用深度学习方法进行图像缺陷检测_使用ResNet50预训练模型来对 太阳能电池板缺陷数据集 12类的缺陷类型进行检测 文章目录1. 数据理解与准备加载和解析XML标签文件2. 数据预处理图像预处理3. 模型选择与训练4. 模型评估与优化5. 测试与推理特定缺陷类型的处理太阳能电池板缺陷…...

别再死记硬背公式了!用DCM模式反激电源设计,手把手教你搞定变压器漏感与尖峰吸收

DCM模式反激电源设计实战&#xff1a;从漏感机理到尖峰吸收方案优化 反激电源作为开关电源家族中最具性价比的隔离方案&#xff0c;在消费电子、工业控制和物联网设备中占据着重要地位。但许多工程师在初次设计时&#xff0c;常被MOSFET开关波形上的诡异振铃、难以预测的电压尖…...

从Java到前端:一名全栈开发者的成长之路

从Java到前端&#xff1a;一名全栈开发者的成长之路 一、面试开始 面试官&#xff08;严肃但温和&#xff09;&#xff1a; 嗨&#xff0c;你好&#xff0c;我是张伟&#xff0c;目前在一家互联网大厂负责技术招聘。今天来聊聊你的技术背景和项目经验。 应聘者&#xff08;略显…...

中国企业海外人才布局成功案例集锦

导读&#xff1a;当前中国企业全球化已从产品出海迈入组织能力与长期价值构建的深水区&#xff0c;在地缘环境、技术迭代与监管变化的多重影响下&#xff0c;企业面临市场适配、跨区域协同、人才稀缺、能力升级、信任构建等多重挑战&#xff0c;海外人才布局成为全球化成败的核…...

制造业数字化升级:生产全流程企业级智能体落地解决方案 —— 基于LLM+超自动化全栈架构的智改数转深度实战

站在2026年的时间节点回望&#xff0c;全球制造业的数字化转型已经完成了从“单点自动化”向“系统智能化”的质变。随着“十五五”规划中关于“智改数转网联”高级阶段的深入推进&#xff0c;传统的工业软件架构正在被以AI Agent为核心的智能体矩阵所重构。 过去五年&#xff…...

从ESP32到HIFI5:一文搞懂Cadence Xtensa处理器家族那些事儿(含DSP指令集差异)

从ESP32到HIFI5&#xff1a;Cadence Xtensa处理器家族全解析 在嵌入式处理器领域&#xff0c;Xtensa架构以其独特的可配置性和扩展能力脱颖而出。作为Cadence旗下的核心产品线&#xff0c;Xtensa处理器家族涵盖了从通用微控制器到专用DSP的广泛解决方案。本文将深入剖析这一技术…...

从QLabel超链接到桌面集成:Qt中QDesktopServices的5个实战用法(文件、邮件、网页一键打开)

从QLabel超链接到桌面集成&#xff1a;Qt中QDesktopServices的5个实战用法 在桌面应用开发中&#xff0c;系统集成能力往往决定了用户体验的上限。想象一下&#xff1a;用户点击一个链接就能直接打开默认浏览器访问网页&#xff0c;点击邮件地址就能唤起熟悉的邮件客户端&#…...