【iOS逆向】某营业厅算法分析
阅读此文档的过程中遇到任何问题,请关注公众号【移动端Android和iOS开发技术分享
】或加QQ群【812546729
】
1.目标
使用frida stalker分析某营业厅的签名算法。
2.操作环境
mac系统
frida-ios-dump:砸壳
Charles:抓包
已越狱iOS设备:脱壳及frida调试
IDA Pro:静态分析
3.流程
寻找切入点
在账号密码登录页,点击登录,通过Charles抓包获取到关键词为loginAuthCipherAsymmertric,这也就是我们的切入点:
分析过程
使用frida-ios-dump的砸壳命令dump.py com.wemomo.momoappdemo1
砸壳获取到ipa文件,再使用IDA Pro编译ipa文件,然后搜索搜索字符串loginAuthCipherAsymmertric失败,继续搜索userLoginNormal,失败。该应用对字符串都进行了混淆。搜索无果后,只能换个思路,尝试hook NSMutableURLRequest类。
使用frida-trace的frida-trace -UF -m "-[NSMutableURLRequest setHTTPBody:]"
命令跟踪该函数,js代码如下:
{
onEnter(log, args, state) {
var arg2 = new ObjC.Object(args[2])
log(`-[NSMutableURLRequest setHTTPBody:${arg2.bytes().readUtf8String()}]`);
},
onLeave(log, retval, state) {
}
}
点击登录后,获取到的日志如下:
-[NSMutableURLRequest setHTTPBody:ndh=1&t=00%2F00%2F0000%2000%3A00%3A00%200%20-480&c.&v3=baoguang_event&deviceId=7B063D78-C5D8-45A6-8E3D-37B787DEB2CD&hitDate=2022-09-02%2023%3A01%3A52¤tPage=Denglujh-kuandaidenglushouji&v63=101-106&appVersion=4&c25=%E6%B6%88%E6%81%AF%2BSyjh-sytop-message-1_1%2B%28null%29%2B%28null%29&es_timestamp=1662130874519&v60=lo158b3b81&codeVersion=22033101&v65=WIFI&v61=disable&a.&action=trkAppBgAction&OSVersion=iOS%2012.5.5&DeviceName=iPhone7%2C2&RunMode=Application&AppID=CTPocket%209.4.0%20%284%29&CarrierName=%28null%29&Resolution=750x1334&TimeSinceLaunch=2536&.a&lunchtype=aut_lunch&.c&pev2=AMACTION%3AtrkAppBgAction&pageName=CTPocket%2F4&ce=UTF-8&aid=540B88F2280D4599-146C532D0B076319&pe=lnk_o&cp=foreground]
-[NSMutableURLRequest setHTTPBody:{"content":{"fieldData":{"isChinatelecom":"0","phoneNum":"13245678901","authentication":"222222","accountType":"","deviceUid":"ddecc53e1fce414e9e89b6ea47e567e3","systemVersion":"12.5.5","loginAuthCipherAsymmertric":"o4Af5TvC5iV25FhTE9NIZJEiqHLWg+JkcCF4AGp727uhvFydBWvkCz8HauqTDpIoRhpfqLUMLN6Hk1ucBZOPYhCHwm4N\/4PuPsMWZTEbips+uL74ufgeLMci0nIZRmFsCsBrgvUVkebKcRo2yO0DZQ2jtnKe+cG78v6aOHl5ssk=","loginType":"4"},"attach":"iPhone"},"headerInfos":{"broadAccount":"","source":"120002","shopId":"20004","userLoginName":"13245678901","broadToken":"","code":"userLoginNormal","clientType":"#9.4.0#channel50#iPhone 6#","token":"","timestamp":"20220902230115","sourcePassword":"TiqmIZ"}}]
-[NSMutableURLRequest setHTTPBody:ndh=1&t=00%2F00%2F0000%2000%3A00%3A00%200%20-480&c.&v3=hit_event&deviceId=7B063D78-C5D8-45A6-8E3D-37B787DEB2CD&hitDate=2022-09-02%2023%3A01%3A05&c20=%E5%8F%B3%E6%BB%91%E7%99%BB%E5%BD%95&appVersion=4&lastAction=Denglujh-denglu-mima-2_8%5E%E5%8F%B3%E6%BB%91%E7%99%BB%E5%BD%95&method=trkAppButtonClick%20-action%20...&v63=101-106¤tPage=Denglujh-kuandaidenglushouji&es_timestamp=1662130875056&c21=Denglujh-denglu-mima-2_8&v60=lo158b3b81&codeVersion=22033101&v65=WIFI&v61=disable&a.&action=trkAppButtonClick&OSVersion=iOS%2012.5.5&CarrierName=%28null%29&DeviceName=iPhone7%2C2&AppID=CTPocket%209.4.0%20%284%29&RunMode=Application&Resolution=750x1334&TimeSinceLaunch=2537&.a&lunchtype=aut_lunch&prePageAction=hit_event&.c&pev2=AMACTION%3AtrkAppButtonClick&pageName=CTPocket%2F4&ce=UTF-8&aid=540B88F2280D4599-146C532D0B076319&pe=lnk_o&cp=foreground]
搜索登录的账号13245678901后,发现日志里有登录的body信息,在setHTTPBody的js代码里打印堆栈:
{
onEnter(log, args, state) {
var arg2 = new ObjC.Object(args[2])
log(`-[NSMutableURLRequest setHTTPBody:${arg2.bytes().readUtf8String()}]`);
log('NSMutableURLRequest setHTTPBody called from:\n' +
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n') + '\n');
},
onLeave(log, retval, state) {
}
}
获取到的堆栈信息如下:
0x10397f4d8 CTPocket!-[AFJSONRequestSerializer requestBySerializingRequest:withParameters:error:]
0x10397ae50 CTPocket!-[AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:]
0x10394edac CTPocket!-[AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:headers:uploadProgress:downloadProgress:success:failure:]
0x10394e378 CTPocket!-[AFHTTPSessionManager POST:parameters:headers:progress:success:failure:]
0x101b8fae8 CTPocket!-[ESHttpSessionManager postWithHost:urlString:parameters:success:failure:]
0x1015f91c8 CTPocket!-[ESNetworkingManager postWithURLString:parameters:modifiParamsBlock:success:failure:]
0x100c14da4 CTPocket!-[ESLoginService loginWithPhoneNbr:type:code:isChinatelecom:slidingTime:percentage:success:failure:]
0x101f85f58 CTPocket!-[ESBindLoginViewController phoneLoginWithPhoneNbr:type:code:slidingTime:percentage:isChinatelecom:isBind:failureBlock:]
0x101f6a060 CTPocket!-[ESBindLoginViewController phoneLoginViewController:inputView:didSliderWithSlidingTime:Percentage:phoneNbr:passwd:loginType:isChinatelecom:isBind:failureBlock:]
0x102ccb964 CTPocket!-[ESLoginViewController phoneLoginView:inputView:didSliderWithSlidingTime:Percentage:phoneNbr:passwd:loginType:isChinatelecom:isBind:]
0x101261728 CTPocket!-[ESPhoneLoginView passwordInputView:sliderWithSlidingTime:Percentage:phoneNbr:passwd:]
0x101e73d10 CTPocket!-[PasswordInputView commitBtnAction:]
0x1e7091300 UIKitCore!-[UIApplication sendAction:to:from:forEvent:]
0x10400a288 CTPocket!-[UIApplication(AutoTrack) sa_sendAction:to:from:forEvent:]
0x1e6b3a424 UIKitCore!-[UIControl sendAction:to:forEvent:]
0x1e6b3a744 UIKitCore!-[UIControl _sendActionsForEvents:withEvent:]
接下来我们使用frida-trace工具,对以上调用栈进行逐个跟踪并打印入参,最终确定loginAuthCipherAsymmertric参数在[ESLoginService loginWithPhoneNbr:type:code:isChinatelecom:slidingTime:percentage:success:failure:]方法里生成的,打开IDA Pro并找到该方法,代码如下:
id __cdecl -[ESLoginService loginWithPhoneNbr:type:code:isChinatelecom:slidingTime:percentage:success:failure:](ESLoginService *self, SEL a2, id a3, signed __int64 a4, id a5, id a6, id a7, id a8, id a9, id a10)
{
id v10; // x19
id v11; // x20
id v12; // x25
id v13; // x21
ESLoginService *v14; // x24
__int64 v15; // x1
__int64 v16; // x1
__int64 v17; // x1
__int64 v18; // x1
__int64 v19; // x1
__int64 v20; // x1
void *v21; // x0
__int64 v22; // x25
void *v23; // x0
unsigned int v24; // off
signed int v25; // w8
v10 = a8;
v11 = a7;
v12 = a6;
v13 = a5;
v14 = self;
objc_retain(a3, a2);
objc_retain(a9, v15);
objc_retain(a10, v16);
objc_retain(v10, v17);
objc_retain(v11, v18);
objc_retain(v12, v19);
objc_retain(v13, v20);
v21 = objc_msgSend(&OBJC_CLASS___NSDate, "date");
v22 = objc_retainAutoreleasedReturnValue(v21);
-[ESLoginService setRequestDate:](v14, "setRequestDate:", v22);
objc_release(v22);
v23 = (void *)((__int64 (__fastcall *)(void *))((char *)off_105153068 + 92708870))(&OBJC_CLASS___NSDateFormatter);
objc_msgSend(v23, "init");
v24 = __ldar((unsigned int *)&dword_10577A424);
if ( (unsigned int)&dword_10577A424 )
v25 = 7;
else
v25 = 34;
JUMPOUT(__CS__, (char *)*(&off_105153070 + v25) - dword_1051531F0[v25]);
}
傻眼了了吧。 JUMPOUT,也就是经常逆向会遇到的跳表,需要手动恢复。在这,我们使用frida stalker来跟踪该函数。ts代码如下:
var addr = 0x0000000029FD08 // loginWithPhoneNbr函数的起始地址
var mainModule = Process.enumerateModules()[0];
console.log(JSON.stringify(mainModule));
var mainName: string = mainModule.name;
var baseAddr = Module.findBaseAddress(mainName)!;
Interceptor.attach(baseAddr.add(addr), {
onEnter: function(args) {
console.log(addr.toString(16), "= loginWithPhoneNbr onEnter =");
var tid = Process.getCurrentThreadId();
Stalker.follow(tid, {
events: {
call: true, // CALL instructions: yes please
ret: false, // RET instructions
exec: false, // all instructions: not recommended as it's
block: false, // block executed: coarse execution trace
compile: false // block compiled: useful for coverage
},
transform: (iterator: StalkerArm64Iterator) => {
let instruction = iterator.next();
const startAddress = instruction!.address;
var isAppCode = startAddress.compare(baseAddr.add(addr)) >= 0 && startAddress.compare(baseAddr.add(addr).add(10000)) === -1;
do {
if (isAppCode) {
if (instruction!.mnemonic === "bl") {
iterator.putCallout((ctx) => {
var arm64Context = ctx as Arm64CpuContext;
console.log("bl x0 = " + new ObjC.Object(arm64Context.x0))
console.log("bl x1 = " + arm64Context.x1.readCString())
});
}
}
iterator.keep();
} while ((instruction = iterator.next()) !== null);
}
})
}, onLeave: function(retval) {
console.log("retval:", new ObjC.Object(retval))
console.log(addr.toString(16), "= loginWithPhoneNbr onLeave =");
}
});
获取到的关键日志如下:
29fd08 = loginWithPhoneNbr onEnter =
bl x0 = Utils
bl x1 = createRSAStringWithPhone:authentication:timestamp:slidingTime:percentage:
bl x0 = s21NZBfNx8ndPADDLDJCxCUOdWo45EL8jNr6TnHcwKwfnahCFpLGjXkZkhbGj2CZODR3LVjabCRw6Li3SLcvLtA6g0meKbUTgQzANtn9y2ttg9Svj9flxj9k18Ju5EBjloSbdd4ee4o0rHgn9W0iSSDs4zwKsqm+rOxYDZFHgWI=
bl x1 = autorelease
bl x0 = 0.000000
bl x1 = null
bl x0 = 0
bl x1 = null
bl x0 = NSMutableDictionary
bl x1 = dictionary
bl x0 = {
}
bl x1 = autorelease
bl x0 = {
}
bl x1 = setObject:forKey:
bl x0 = {
accountType = "";
}
bl x1 = setObjectOrNil:forKey:
bl x0 = 222222
bl x1 = copyWithZone:
bl x0 = ESGlobalFactory
bl x1 = sharedInstance
bl x0 = <ESGlobalFactory: 0x282e568b0>
bl x1 = sharedInstance
bl x0 = <ESGlobalFactory: 0x282e568b0>
bl x1 = deviceInfo
bl x0 = <ESDeviceInfo: 0x28225e120>
bl x1 = deviceInfo
bl x0 = <ESDeviceInfo: 0x28225e120>
bl x1 = uuidForDevice
bl x0 = ddecc53e1fce414e9e89b6ea47e567e3
bl x1 = autorelease
bl x0 = {
accountType = "";
authentication = 222222;
}
bl x1 = setObjectOrNil:forKey:
bl x0 = ddecc53e1fce414e9e89b6ea47e567e3
bl x1 = copyWithZone:
bl x0 = <ESDeviceInfo: 0x28225e120>
bl x1 = release
bl x0 = <ESGlobalFactory: 0x282e568b0>
bl x1 = release
bl x0 = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
}
bl x1 = setObjectOrNil:forKey:
bl x0 = 0
bl x1 = copyWithZone:
bl x0 = NSString
bl x1 = stringWithFormat:
bl x0 = 4
bl x1 = autorelease
bl x0 = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
isChinatelecom = 0;
}
bl x1 = setObjectOrNil:forKey:
bl x0 = 4
bl x1 = copyWithZone:
bl x0 = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
isChinatelecom = 0;
loginType = 4;
}
bl x1 = setObjectOrNil:forKey:
bl x0 = UIDevice
bl x1 = currentDevice
bl x0 = <UIDevice: 0x2820598e0>
bl x1 = currentDevice
bl x0 = <UIDevice: 0x2820598e0>
bl x1 = systemVersion
bl x0 = 12.5.5
bl x1 = X7Lyw9oGPgMDQ
bl x0 = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
isChinatelecom = 0;
loginType = 4;
phoneNum = 13245678901;
}
bl x1 = setObjectOrNil:forKey:
bl x0 = 12.5.5
bl x1 = 0��ו�
bl x0 = <UIDevice: 0x2820598e0>
bl x1 = 0��ו�
bl x0 = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
isChinatelecom = 0;
loginType = 4;
phoneNum = 13245678901;
systemVersion = "12.5.5";
}
bl x1 = setObjectOrNil:forKey:
bl x0 = ESDataAccessFactory
bl x1 = sharedInstance
bl x0 = <ESDataAccessFactory: 0x280472460>
bl x1 = sharedInstance
bl x0 = <ESDataAccessFactory: 0x280472460>
bl x1 = highFrequencyNetworkingManager
bl x0 = <ESNetworkingManager: 0x282e9cc90>
bl x1 = highFrequencyNetworkingManager
bl x0 = <__NSStackBlock__: 0x16f4f0c28>
bl x1 = highFrequencyNetworkingManager
bl x0 = <__NSStackBlock__: 0x16f4f0c88>
bl x1 = retain
bl x0 = 20220905003215
bl x1 = retain
bl x0 = 13245678901
bl x1 = null
bl x0 = <ESNetworkingManager: 0x282e9cc90>
bl x1 = postWithURLString:parameters:modifiParamsBlock:success:failure:
bl x0 = {
content = {
attach = iPhone;
fieldData = {
accountType = "";
authentication = 222222;
deviceUid = ddecc53e1fce414e9e89b6ea47e567e3;
isChinatelecom = 0;
loginAuthCipherAsymmertric = "s21NZBfNx8ndPADDLDJCxCUOdWo45EL8jNr6TnHcwKwfnahCFpLGjXkZkhbGj2CZODR3LVjabCRw6Li3SLcvLtA6g0meKbUTgQzANtn9y2ttg9Svj9flxj9k18Ju5EBjloSbdd4ee4o0rHgn9W0iSSDs4zwKsqm+rOxYDZFHgWI=";
loginType = 4;
phoneNum = 13245678901;
systemVersion = "12.5.5";
};
};
headerInfos = {
broadAccount = "";
broadToken = "";
clientType = "#9.4.0#channel50#iPhone 6#";
code = userLoginNormal;
shopId = 20004;
source = 120002;
sourcePassword = TiqmIZ;
timestamp = 20220905003218;
token = "";
userLoginName = "";
};
}
bl x1 = a���
结果
通过日志,我们可以发现loginAuthCipherAsymmertric参数是使用Utils类的createRSAStringWithPhone:authentication:timestamp:slidingTime:percentage:方法生成的,伪代码如下:
id __cdecl +[Utils createRSAStringWithPhone:authentication:timestamp:slidingTime:percentage:](Utils_meta *self, SEL a2, id a3, id a4, id a5, id a6, id a7)
{
v7 = a7;
v8 = a5;
v9 = a4;
v10 = a3;
v11 = self;
v12 = objc_retain(a6, a2);
v14 = objc_retain(v7, v13);
v16 = (void *)objc_retain(v8, v15);
v18 = objc_retain(v9, v17);
v20 = objc_retain(v10, v19);
v21 = +[ESGlobalFactory sharedInstance](&OBJC_CLASS___ESGlobalFactory, "sharedInstance");
v22 = (void *)objc_retainAutoreleasedReturnValue(v21);
v23 = v22;
v24 = objc_msgSend(v22, "deviceInfo");
v25 = (void *)objc_retainAutoreleasedReturnValue(v24);
v26 = v25;
v27 = objc_msgSend(v25, "uuidForDevice");
v28 = objc_retainAutoreleasedReturnValue(v27);
v29 = +[Utils substring:ToIndex:](&OBJC_CLASS___Utils, "substring:ToIndex:", v28, 12LL);
v30 = objc_retainAutoreleasedReturnValue(v29);
v31 = +[Utils deviceName](&OBJC_CLASS___Utils, "deviceName");
v32 = objc_retainAutoreleasedReturnValue(v31);
v33 = v32;
v34 = +[Utils substring:ToIndex:](&OBJC_CLASS___Utils, "substring:ToIndex:", v32, 10LL);
v35 = objc_retainAutoreleasedReturnValue(v34);
v36 = objc_msgSend(&OBJC_CLASS___UIDevice, "currentDevice");
v37 = (void *)objc_retainAutoreleasedReturnValue(v36);
v38 = v37;
v39 = objc_msgSend(v37, "systemVersion");
v40 = objc_retainAutoreleasedReturnValue(v39);
objc_release(v38);
v41 = +[Utils substring:ToIndex:](&OBJC_CLASS___Utils, "substring:ToIndex:", v40, 5LL);
v42 = objc_retainAutoreleasedReturnValue(v41);
objc_release(v40);
v43 = (void *)objc_alloc(&OBJC_CLASS___NSDateFormatter);
v44 = objc_msgSend(v43, "init");
v45 = v44;
v46 = v44;
objc_msgSend(v44, "setDateFormat:", CFSTR("yyyyMMddHHmmss"));
v47 = (void *)objc_alloc(&OBJC_CLASS___NSLocale);
v48 = objc_msgSend(v47, "initWithLocaleIdentifier:", CFSTR("en_US"));
objc_msgSend(v45, "setLocale:", v48);
v49 = objc_msgSend(v16, "stringByReplacingOccurrencesOfString:withString:", CFSTR(":"), &stru_10480C358);
v50 = objc_retainAutoreleasedReturnValue(v49);
objc_release(v16);
v51 = +[Utils substring:ToIndex:](&OBJC_CLASS___Utils, "substring:ToIndex:", v50, 14LL);
v52 = objc_retainAutoreleasedReturnValue(v51);
v53 = v52;
v54 = v52;
v55 = objc_msgSend(v11, "substring:ToIndex:", v12, 4LL);
v56 = objc_retainAutoreleasedReturnValue(v55);
v57 = objc_msgSend(v11, "substring:ToIndex:", v14, 2LL);
v58 = objc_retainAutoreleasedReturnValue(v57);
v59 = objc_msgSend(v11, "substring:ToIndex:", v18, 6LL);
v60 = objc_retainAutoreleasedReturnValue(v59);
v61 = objc_msgSend(v11, "substring:ToIndex:", v20, 11LL);
v62 = objc_retainAutoreleasedReturnValue(v61);
v63 = objc_msgSend(
&OBJC_CLASS___NSString,
"stringWithFormat:",
CFSTR("%@%@%@%@%@%@%@%@"),
v35,
v42,
v30,
v62,
v53,
v60,
v56,
v58);
v64 = objc_retainAutoreleasedReturnValue(v63);
v65 = +[Utils loginRsaKey2](&OBJC_CLASS___Utils, "loginRsaKey2");
v66 = objc_retainAutoreleasedReturnValue(v65);
v67 = v66;
v68 = +[RSAEncryptor encryptString:publicKey:](&OBJC_CLASS___RSAEncryptor, "encryptString:publicKey:", v64, v66);
v69 = objc_retainAutoreleasedReturnValue(v68);
return (id)objc_autoreleaseReturnValue(v69);
}
这就是生成loginAuthCipherAsymmertric的最终函数。
End
阅读此文档的过程中遇到任何问题,请关注公众号【移动端Android和iOS开发技术分享
】或加QQ群【812546729
】
【iOS逆向】某营业厅算法分析的更多相关文章
- iOS逆向分析app
适合有一定的逆向编程基础的人看. 背景:自动抢红包的脚本工具:cyscript,reveal,class-dump,越狱的pod等. 这里先上一张reveal的分析图: 小结:获取到了真个软件的整体结 ...
- iOS 逆向之ARM汇编
最近对iOS逆向工程很感兴趣. 目前iOS逆向的书籍有: <Hacking and Securing IOS Applications>, <iOS Hacker's Handboo ...
- ios逆向过程中lldb调试技巧
在ios逆向过程中,善于运用lldb,会给逆向带来很大的方便 一般的命令: 1.image list -o -f 看看各个模块在内存中的基址 2.register read r0 读取寄存器r0的 ...
- iOS逆向开发(1):基础工具 | ssh | scp | socat
小白:小程,我一直想问,什么是逆向来着?是逆向行驶吗? 小程:理解为逆向行驶也没错.一般的项目是从无到有,而逆向是从已有的状态入手,分析出已有的流程与结构的手段. iOS上的逆向开发,是一件有趣的事情 ...
- iOS逆向+越狱
感觉本文涉及内容有点多的,但是自己不愿意写太多,就简单的谢谢关于ios上手的东西吧 初级入手不免要用到,pp助手,i4 tools等 iOS逆向-ipa包重签名及非越狱手机安装多个应用 1.常识 我们 ...
- 偏执的iOS逆向研究员:收集全版本的macOS iOS+越狱+内核调试
Intro 虽然“只有偏执狂才能够生存”这句话已经被假药停给毁了,但是作为一只有逼格的高大上的iOS逆向分析研究员,难道如果有现成的macOS/iOS全版本镜像可以下载并且无限“漫游”,难道你就不想来 ...
- iOS逆向实战与工具使用(微信添加好友自动确认)
iOS逆向实战与工具使用(微信添加好友自动确认) 原文链接 源码地址 WeChatPlugin-iOS Mac OS 版微信小助手(远程控制.消息防撤回.自动回复.微信多开) 一.前言 本篇主要实现在 ...
- iOS逆向(五)-ipa包重签名
为什么要重签名? 1.在没有源代码的情况下,你已经对某个应用进行了资源修改(比如修改了启动图或图标等).修改完成以后,如果想要让APP可以正常使用,该APP一定要重新签名然后压缩成IPA文件. 2.如 ...
- iOS逆向系列-脱壳
概述 通过iOS逆向系列-逆向App中使用class-dump工具导出App的Mach-O文件所有头文件.Hopper工具分析App的Mach-O文件代码大概实现.但是这些前体是App的Mach-O没 ...
- iOS逆向系列-逆向APP思路
界面分析 通过Cycript.Reveal. 对于Reveal安装配置可参考配置iOS逆向系列-Reveal 通过Reveal找到内存中的UI对象 静态分析 开发者编写的所有代码最终编译链接到Mach ...
随机推荐
- KingbaseES V8R6C5B041 sys_backup.sh单实例备份案例
数据库版本: test=# select version(); version ---------------------------------------------------------- ...
- KingbaseES 全局索引
概述:在分区表上创建的索引可分为全局索引和本地索引.全局索引包括全局非分区索引(Global Nonpartitioned Indexes)和全局分区索引(Global Partitioned Ind ...
- maven-scope属性
Maven 中的 scope 属性解释 <dependency> <groupId>org.glassfish.web</groupId> <artifact ...
- 【项目实战】CNN手写识别复杂模型的构造
感谢视频教程:https://www.bilibili.com/video/BV1Y7411d7Ys?p=11 这里开一篇新博客不仅仅是因为教程视频单独出了1p,也是因为这是一种代码编写的套路,特在此 ...
- 开源 Web 相册程序: Photoview 和数据可视化生成工具:Datawrapper
Photoview Photoview是一个开源 Web 相册程序,Go 语言写的,使用 Docker 安装,可以用来快速架设个人相册. github地址:https://github.com/pho ...
- 解决inode满
登陆服务器运行df -i 然后运行 for i in /*; do echo $i; find $i |wc -l|sort -nr; done 看看每个文件夹下面的数量 最后发现是/var/spoo ...
- 14. Fluentd输出插件:out_forward用法详解
out_forward是一个带缓存的输出插件,用于向其他节点转发日志事件,并支持转发节点之间的负载均衡和自动故障切换. out_forward支持至多一次和至少一次传输模式,默认为至多一次. out_ ...
- Netty 学习(六):创建 NioEventLoopGroup 的核心源码说明
Netty 学习(六):创建 NioEventLoopGroup 的核心源码说明 作者: Grey 原文地址: 博客园:Netty 学习(六):创建 NioEventLoopGroup 的核心源码说明 ...
- 基于.NetCore开发博客项目 StarBlog - (18) 实现本地Typora文章打包上传
前言 九月太忙,只更新了三篇文章,本来这个功能是从九月初就开始做的,结果一直拖到现在国庆假期才有时间完善并且写文章~ 之前我更新了几篇关于 Python 的文章,有朋友留言问是不是不更新 .Net 了 ...
- 220722 T3 石子染色 (背包)
序列s中的数就是要选的堆的编号,假设要选的有i个石子,这i个染为红色,剩下j个染为蓝色,i+j=x,i=x-j,那么对答案的贡献是|x-2j|.那么只要我们选的有i个石子,贡献就是这么多,所以我们可以 ...