【Android逆向】破解看雪9月算法破解第三题
这题的目标是算法还原,并写出注册机
1. 9月份算法第一题.apk 安装到手机
2. 随意输入账号密码,提示错误
3. apk拖入到jadx中
public native boolean register(String str, String str2);
static {
System.loadLibrary("register");
}
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
requestWindowFeature(1);
getWindow().setFlags(1024, 1024);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
this.imageView = (ImageView) findViewById(R.id.imageView);
this.textView = (TextView) findViewById(R.id.textView);
this.edt_password = (EditText) findViewById(R.id.edt_password);
this.edt_username = (EditText) findViewById(R.id.edt_username);
this.btn_register = (Button) findViewById(R.id.btn_register);
Button button = (Button) findViewById(R.id.btn_tips);
this.btn_tips = button;
button.setOnClickListener(this);
this.btn_register.setOnClickListener(this);
if (Integer.parseInt(new SimpleDateFormat("hh").format(Long.valueOf(System.currentTimeMillis()))) >= 16) {
this.imageView.setImageResource(R.drawable.good_night_img);
this.textView.setText("Night");
}
......
@Override // android.view.View.OnClickListener
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_register /* 2131296354 */:
String obj = this.edt_username.getText().toString();
String obj2 = this.edt_password.getText().toString();
if (obj.equals("") || obj2.equals("")) {
Toasty.error((Context) this, (CharSequence) "请输入用户名和密码", 1, true).show();
return;
} else if (obj.length() < 6 || obj.length() > 20) {
Toasty.error((Context) this, (CharSequence) "请输入正确用户名", 1, true).show();
return;
} else if (!register(obj, obj2)) {
Toasty.error((Context) this, (CharSequence) "注册失败", 1, true).show();
return;
} else {
Toasty.success((Context) this, (CharSequence) "注册成功,恭喜恭喜", 1, true).show();
return;
}
case R.id.btn_tips /* 2131296355 */:
Toasty.info((Context) this, (CharSequence) "题目要求:逆向这个APP,查看使用了哪些算法,并做一个注册机\n可横向华滑动背景调整主题哦~", 1, true).show();
return;
default:
return;
}
}
4. 那么答案在libregister.so中, IDA打开它,查看关键函数
bool __fastcall sub_868(const char *username, const char *password)
{
__int64 len; // x0
void *v5; // x20
__int64 v6; // x0
__int128 v8[6]; // [xsp+0h] [xbp-D0h] BYREF
int v9; // [xsp+60h] [xbp-70h]
char v10[8]; // [xsp+68h] [xbp-68h] BYREF
__int64 v11; // [xsp+70h] [xbp-60h]
char v12; // [xsp+78h] [xbp-58h]
__int128 v13; // [xsp+80h] [xbp-50h] BYREF
__int64 md5_result[2]; // [xsp+90h] [xbp-40h] BYREF
char v15; // [xsp+A0h] [xbp-30h]
__int64 v16; // [xsp+A8h] [xbp-28h]
v16 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
md5_result[0] = 0LL;
md5_result[1] = 0LL;
v15 = 0;
len = strlen(username);
sub_26EC(username, len, md5_result);
*(_QWORD *)v10 = 0LL;
v11 = 0LL;
v12 = 0;
v13 = aDtayydsDtayyds;
v5 = (void *)sub_1A40(16LL);
sub_181C(&v13, v5);
sub_1AA4(md5_result, v10, v5);
free(v5);
v9 = 0;
memset(v8, 0, sizeof(v8));
v6 = __strlen_chk(v10, 0x11u);
base64_sub_A0C(v10, v6, v8);
return strcmp((const char *)v8, password) == 0;
}
5. 先看sub_26EC
其中看到一串常量
v13 = 0xEFCDAB89;
v14 = 0x98BADCFE;
v15 = 0x67452301;
v16 = 0x10325476;
这就是MD5算法的特征,怀疑就是MD5算法,hook看一下
frida代码
function main() {
Java.perform(function () {
hookCheck();
Java.choose('com.r0ysue.a202109crakeme.MainActivity', {
onMatch: function(instance) {
var username = "1234567890"
var password = "123456"
instance.register(username, password)
},
onComplete: function() {
}
})
})
}
function hookCheck() {
var lib_hanlder = Process.findModuleByName("libregister.so");
console.log("lib_handler: " + lib_hanlder.base)
if (lib_hanlder) {
//64位 不加一
var addr_hook = lib_hanlder.base.add(0x00000000000008E8)
Interceptor.attach(addr_hook,{
onEnter: function(args) {
console.log(" === hook before")
console.log("=== context:" + JSON.stringify(this.context))
console.log("=== context.x0:" + print_dump(this.context.x0))
console.log("==== 对比 e807f1fcf82d132f9bb018ca6738a19f")
// Memory.protect(this.context.r1, 1024, 'rw-')
// this.context.r1.writeUtf8String("REAL")
// console.log("=== r1:" + this.context.r1.readCString())
},
onLeave:function(retVal) {
console.log(" === hook after: ")
//print_dump(retVal, 128)
//console.log("=== after r1:" + this.context.r1.readCString())
}
})
}
}
function print_dump(arg, size) {
console.log(hexdump(arg, {
offset: 0,
length: size,
header: true,
ansi: true
}))
}
setTimeout(main, 1000)
日志
=== hook before
=== context:{"pc":"0x777f8048e8","sp":"0x7780642f50","x0":"0x7780642fe0","x1":"0x7780642fb8","x2":"0x779c454600","x3":"0xad","x4":"0xd0","x5":"0xa","x6":"0x0","x7":"0x0","x8":"0x777f819000","x9":"0x2c","x10":"0x2c","x11":"0x777f806b00","x12":"0x777f809000","x13":"0x777f809005","x14":"0x777f809008","x15":"0xab","x16":"0x7826c6e000","x17":"0x7780f3e330","x18":"0x0","x19":"0x779c4110c8","x20":"0x779c454600","x21":"0x7780645588","x22":"0x779c433130","x23":"0x779c4110c8","x24":"0xc","x25":"0x7780645588","x26":"0x779c4a08a0","x27":"0x7780645588","x28":"0x7780645588","fp":"0x7780643020","lr":"0x777f8048dc"}
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7780642fe0 e8 07 f1 fc f8 2d 13 2f 9b b0 18 ca 67 38 a1 9f .....-./....g8..
7780642ff0 00 00 00 00 00 00 00 00 21 cb 42 b8 90 0f ab 02 ........!.B.....
7780643000 88 30 64 80 77 00 00 00 88 30 64 80 77 00 00 00 .0d.w....0d.w...
==== 对比 e807f1fcf82d132f9bb018ca6738a19f
利用在线md5验证,发现确实md5算法
6. 再看sub_1A40和sub_181C
在sub_181C 中看到全局数组unk_2B00, 取前面几个值63 7C 77 7B F2 6B 6F C5 搜索引擎搜索,发现是AES的sbox表,说明这里是AES算法特征,github搜索AES算法实现,发现代码与https://github.com/dhuertas/AES类似sub_1A40对应init, sub_181C对应expansion,sub_1AA4对应aes_cipher
7. 再看sub_A0C, 直接发现其字典数组,说明这是一个base64算法
.rodata:0000000000002A40 41 42 43 44 45 46 47 48 49 4A+aAbcdefghijklmn DCB "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
.rodata:0000000000002A40 4B 4C 4D 4E 4F 50 51 52 53 54+ ; DATA XREF: base64_sub_A0C+4↑o
.rodata:0000000000002A40 55 56 57 58 59 5A 61 62 63 64+ ; base64_sub_A0C+1C↑o
8 证明猜想,编写frida验证
function main() {
Java.perform(function () {
hookCheck();
Java.choose('com.r0ysue.a202109crakeme.MainActivity', {
onMatch: function(instance) {
var username = "1234567890"
var password = "123456"
instance.register(username, password)
},
onComplete: function() {
}
})
})
}
function hookCheck() {
var lib_hanlder = Process.findModuleByName("libregister.so");
console.log("lib_handler: " + lib_hanlder.base)
if (lib_hanlder) {
//64位 不加一
var addr_hook = lib_hanlder.base.add(0x00000000000008E8)
Interceptor.attach(addr_hook,{
onEnter: function(args) {
console.log(" === hook before")
console.log("=== context:" + JSON.stringify(this.context))
console.log("=== context.x0:" + print_dump(this.context.x0))
console.log("==== 对比 e807f1fcf82d132f9bb018ca6738a19f")
// Memory.protect(this.context.r1, 1024, 'rw-')
// this.context.r1.writeUtf8String("REAL")
// console.log("=== r1:" + this.context.r1.readCString())
},
onLeave:function(retVal) {
console.log(" === hook after: ")
//print_dump(retVal, 128)
//console.log("=== after r1:" + this.context.r1.readCString())
}
})
var aes_hook = lib_hanlder.base.add(0x0000000000000920)
Interceptor.attach(aes_hook,{
onEnter: function(args) {
console.log(" === aes hook before")
console.log("=== context:" + JSON.stringify(this.context))
console.log("=== context.x0:" + print_dump(this.context.x0))
console.log("=== 0be6e80d12c7780a10ace20c02728350")
},
onLeave:function(retVal) {
console.log(" === hook after: ")
//print_dump(retVal, 128)
//console.log("=== after r1:" + this.context.r1.readCString())
}
})
var base64_hook = lib_hanlder.base.add(0x000000000000092C)
Interceptor.attach(base64_hook,{
onEnter: function(args) {
console.log(" === base64 hook before")
console.log("=== context:" + JSON.stringify(this.context))
console.log("=== context.x0:" + print_dump(this.context.x0))
},
onLeave:function(retVal) {
console.log(" === hook after: ")
//print_dump(retVal, 128)
//console.log("=== after r1:" + this.context.r1.readCString())
}
})
}
}
function print_dump(arg, size) {
console.log(hexdump(arg, {
offset: 0,
length: size,
header: true,
ansi: true
}))
}
setTimeout(main, 1000)
日志
=== hook before
=== context:{"pc":"0x777f8048e8","sp":"0x7780642f50","x0":"0x7780642fe0","x1":"0x7780642fb8","x2":"0x779c454600","x3":"0xad","x4":"0xd0","x5":"0xa","x6":"0x0","x7":"0x0","x8":"0x777f819000","x9":"0x2c","x10":"0x2c","x11":"0x777f806b00","x12":"0x777f809000","x13":"0x777f809005","x14":"0x777f809008","x15":"0xab","x16":"0x7826c6e000","x17":"0x7780f3e330","x18":"0x0","x19":"0x779c4110c8","x20":"0x779c454600","x21":"0x7780645588","x22":"0x779c433130","x23":"0x779c4110c8","x24":"0xc","x25":"0x7780645588","x26":"0x779c4a08a0","x27":"0x7780645588","x28":"0x7780645588","fp":"0x7780643020","lr":"0x777f8048dc"}
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7780642fe0 e8 07 f1 fc f8 2d 13 2f 9b b0 18 ca 67 38 a1 9f .....-./....g8..
7780642ff0 00 00 00 00 00 00 00 00 21 cb 42 b8 90 0f ab 02 ........!.B.....
7780643000 88 30 64 80 77 00 00 00 88 30 64 80 77 00 00 00 .0d.w....0d.w...
7780643010 c0 c6 41 9c 77 00 00 00 8c 30 64 80 77 00 00 00 ..A.w....0d.w...
7780643020 60 30 64 80 77 00 00 00 c0 49 80 7f 77 00 00 00 `0d.w....I..w...
7780643030 0c 00 00 00 00 00 00 00 e2 53 df 7f 77 00 00 00 .........S..w...
7780643040 b0 33 64 80 77 00 00 00 00 08 4a 9c 77 00 00 00 .3d.w.....J.w...
7780643050 20 ad 1b a5 77 00 00 00 00 08 4a 9c 77 00 00 00 ...w.....J.w...
7780643060 58 31 64 80 77 00 00 00 d8 80 91 7f 77 00 00 00 X1d.w.......w...
7780643070 38 21 cb 25 78 00 00 00 00 00 00 00 00 00 00 00 8!.%x...........
7780643080 03 00 00 00 e8 04 28 1b e0 95 e6 12 00 96 e6 12 ......(.........
7780643090 0e 00 00 00 00 00 00 00 a0 71 fe 8c 77 00 00 00 .........q..w...
77806430a0 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 f0 3f .......?.......?
77806430b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
77806430c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
77806430d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
=== context.x0:undefined
==== 对比 e807f1fcf82d132f9bb018ca6738a19f
=== aes hook before
=== context:{"pc":"0x777f804920","sp":"0x7780642f50","x0":"0x7780642fb8","x1":"0x10","x2":"0x7780642f50","x3":"0x2ab0f90b842cb00","x4":"0x0","x5":"0x10","x6":"0x1aa0e8fb741c9ff","x7":"0x7fff7fffff7fff7f","x8":"0x101010101010101","x9":"0x2ab0f90b842cb21","x10":"0x54","x11":"0xa0","x12":"0xc","x13":"0x50","x14":"0xab","x15":"0xb","x16":"0x7826c6e000","x17":"0x7780f3e3d0","x18":"0x0","x19":"0x779c4110c8","x20":"0x779c454600","x21":"0x7780645588","x22":"0x779c433130","x23":"0x779c4110c8","x24":"0xc","x25":"0x7780645588","x26":"0x779c4a08a0","x27":"0x7780645588","x28":"0x7780645588","fp":"0x7780643020","lr":"0x777f804914"}
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7780642fb8 0b e6 e8 0d 12 c7 78 0a 10 ac e2 0c 02 72 83 50 ......x......r.P
7780642fc8 00 cb 42 b8 90 0f ab 02 64 74 61 79 79 64 73 21 ..B.....dtayyds!
7780642fd8 64 74 61 79 79 64 73 21 e8 07 f1 fc f8 2d 13 2f dtayyds!.....-./
7780642fe8 9b b0 18 ca 67 38 a1 9f 00 00 00 00 00 00 00 00 ....g8..........
7780642ff8 21 cb 42 b8 90 0f ab 02 88 30 64 80 77 00 00 00 !.B......0d.w...
7780643008 88 30 64 80 77 00 00 00 c0 c6 41 9c 77 00 00 00 .0d.w.....A.w...
7780643018 8c 30 64 80 77 00 00 00 60 30 64 80 77 00 00 00 .0d.w...`0d.w...
7780643028 c0 49 80 7f 77 00 00 00 0c 00 00 00 00 00 00 00 .I..w...........
7780643038 e2 53 df 7f 77 00 00 00 b0 33 64 80 77 00 00 00 .S..w....3d.w...
7780643048 00 08 4a 9c 77 00 00 00 20 ad 1b a5 77 00 00 00 ..J.w... ...w...
7780643058 00 08 4a 9c 77 00 00 00 58 31 64 80 77 00 00 00 ..J.w...X1d.w...
7780643068 d8 80 91 7f 77 00 00 00 38 21 cb 25 78 00 00 00 ....w...8!.%x...
7780643078 00 00 00 00 00 00 00 00 03 00 00 00 e8 04 28 1b ..............(.
7780643088 e0 95 e6 12 00 96 e6 12 0e 00 00 00 00 00 00 00 ................
7780643098 a0 71 fe 8c 77 00 00 00 00 00 00 00 00 00 f0 3f .q..w..........?
77806430a8 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 00 .......?........
=== context.x0:undefined
=== 0be6e80d12c7780a10ace20c02728350
=== base64 hook before
=== context:{"pc":"0x777f80492c","sp":"0x7780642f50","x0":"0x7780642f50","x1":"0x779c4110c8","x2":"0x7780642f50","x3":"0x2ab0f90b842cb00","x4":"0x0","x5":"0x10","x6":"0x1aa0e8fb741c9ff","x7":"0x7fff7fffff7fff7f","x8":"0x41","x9":"0x16","x10":"0x17","x11":"0x3d","x12":"0x1","x13":"0x50","x14":"0x1","x15":"0x14","x16":"0x7826c6e000","x17":"0x7780f3e470","x18":"0x0","x19":"0x779c4110c8","x20":"0x779c454600","x21":"0x7780645588","x22":"0x779c433130","x23":"0x779c4110c8","x24":"0xc","x25":"0x7780645588","x26":"0x779c4a08a0","x27":"0x7780645588","x28":"0x7780645588","fp":"0x7780643020","lr":"0x7778ae7138"}
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
7780642f50 43 2b 62 6f 44 52 4c 48 65 41 6f 51 72 4f 49 4d C+boDRLHeAoQrOIM
7780642f60 41 6e 4b 44 55 41 3d 3d 00 00 00 00 00 00 00 00 AnKDUA==........
7780642f70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7780642f80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7780642f90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7780642fa0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
7780642fb0 00 00 00 00 77 00 00 00 0b e6 e8 0d 12 c7 78 0a ....w.........x.
7780642fc0 10 ac e2 0c 02 72 83 50 00 cb 42 b8 90 0f ab 02 .....r.P..B.....
7780642fd0 64 74 61 79 79 64 73 21 64 74 61 79 79 64 73 21 dtayyds!dtayyds!
7780642fe0 e8 07 f1 fc f8 2d 13 2f 9b b0 18 ca 67 38 a1 9f .....-./....g8..
7780642ff0 00 00 00 00 00 00 00 00 21 cb 42 b8 90 0f ab 02 ........!.B.....
7780643000 88 30 64 80 77 00 00 00 88 30 64 80 77 00 00 00 .0d.w....0d.w...
7780643010 c0 c6 41 9c 77 00 00 00 8c 30 64 80 77 00 00 00 ..A.w....0d.w...
7780643020 60 30 64 80 77 00 00 00 c0 49 80 7f 77 00 00 00 `0d.w....I..w...
7780643030 0c 00 00 00 00 00 00 00 e2 53 df 7f 77 00 00 00 .........S..w...
7780643040 b0 33 64 80 77 00 00 00 00 08 4a 9c 77 00 00 00 .3d.w.....J.w...
用在线工具对比发现,确实是md5处理后 再aes处理 再base64处理,得到注册码
9 编写注册机
import hashlib
from Crypto.Cipher import AES
import base64
input = "1234567890"
hl = hashlib.md5()
hl.update(input.encode("utf-8"))
md5_data = hl.hexdigest()
key = '64746179796473216474617979647321'
key = bytes.fromhex(key)
aes = AES.new(key, AES.MODE_ECB)
aes_en = aes.encrypt(bytes.fromhex(md5_data))
l = [hex(int(i)) for i in aes_en]
print(" ".join(l))
encrypted_text = str(base64.encodebytes(aes_en), encoding='utf8').replace('\n', '')
print(encrypted_text)
【Android逆向】破解看雪9月算法破解第三题的更多相关文章
- 看雪.TSRC 2017CTF秋季赛第三题
看雪.TSRC 2017CTF秋季赛第三题 wp 这是一道很简单的题,反调试的坑略多.这道题采用了很多常用的反调试手段,比如调用IsDebuggerPresent.进程名检查等等.另外也有利用SEH的 ...
- off-by-one&doublefree. 看雪10月ctf2017 TSRC 第四题赛后学习
off-by-one 0x00 发现漏洞 1.off-by-one 在massage函数中,如图所示,可以修改的字节数比原内存大小多了一个字节 2.悬挂指针 可以看到,在free堆块的时候,没有清空指 ...
- 2019看雪CTF 晋级赛Q2第四题wp
上次参加2019看雪CTF 晋级赛Q2卡在了这道题上,虽然逆出算法,但是方程不会解,哈哈哈哈,果然数学知识很重要呀,现在记录一下. 首先根据关键信息,根据错误提示字符串定位到这里: 1 int __t ...
- Android逆向之so的半自动化逆向
因为工作需要,转型干android逆向,有几个月了.不过对于so的逆向,任然停留在,难难难的阶段,虽然上次自己还是逆向了一个15k左右的小so文件,但是,那个基本是靠,一步一步跟代码,查看堆栈信息来自 ...
- 天眼查sign 算法破解
天眼查sign 算法破解 最近真的在sign算法破解上一去不复返 前几天看过了企查查的sign破解 今天再看看天眼查的sign算法破解,说的好(zhuang)点(bi)就是破解,不好的就是这是很简单的 ...
- Android逆向之旅---Android中锁屏密码算法解析以及破解方案
一.前言 最近玩王者荣耀,下载了一个辅助样本,结果被锁机了,当然破解它很简单,这个后面会详细分析这个样本,但是因为这个样本引发出的欲望就是解析Android中锁屏密码算法,然后用一种高效的方式制作锁机 ...
- Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)
Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码) 来源 https://blog.csdn.net/jiangwei0910410003/article/details/51 ...
- Android 逆向实战篇(加密数据包破解)
1. 实战背景由于工作需要,要爬取某款App的数据,App的具体名称此处不便透露,避免他们发现并修改加密逻辑我就得重新破解了. 爬取这款App时发现,抓包抓到的数据是加密过的,如图1所示(原数据较长, ...
- 看雪论坛 破解exe 看雪CTF2017第一题分析-『CrackMe』-看雪安全论坛
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 逆向 黑客 破解 学习 论坛 『CrackMe』 http://bbs.pediy.co ...
- 启xin宝app的token算法破解——逆向篇(二)
启xin宝app的token算法破解--抓包分析篇(一)文章已经对该app进行了抓包分析,现在继续对它进行逆向. 对于一个app而言,我们要逆向app,需要知道什么呢? 逆向工具 Java基础,甚至c ...
随机推荐
- [转帖]TIDB - TIDB集群的扩容和缩容及TIUP指令说明
一.TIUP工具简介 前面介绍了使用TIUP搭建TIDB集群,本篇文章详细介绍下使用TIUP对集群进行扩容和缩容. 在面对双十一这种流量突峰的场景,我们平常的TIDB集群有可能承受不住,因此需要提前进 ...
- [转帖]Jmeter 参数化
一.Jmeter参数化概念 当使用JMeter进行测试时,测试数据的准备是一项重要的工作.若要求每次迭代的数据不一样时,则需进行参数化,然后从参数化的文件中来读取测试数据. 参数化是自动化测试脚本的一 ...
- [转帖]gdb 常用命令
https://www.cnblogs.com/xvic/p/15997498.html 栈信息 不管是操作转储文件还是用GDB设置断点进行调试,都可以输入 (gdb)bt 打印栈内容进行查看.一般的 ...
- 【原创】linux为什么不是实时操作系统
一.什么是实时操作系统(RTOS)? 可参见本博客之前的文章: 什么是实时 实时的分类 常见的RTOS latency和jitter 总结一下,实时其实说的是系统响应事件需要的时间的确定性,时间必须确 ...
- charles如何抓取https请求
我们都知道charles下载安装后只能抓取http请求,要想抓取https请求需要下载安装证书 下面介绍pc端和移动端的配置方法 一.pc端(win) 1.打开charles,点击help>SS ...
- K3S +Helm+NFS最小化测试安装部署只需十分钟
作者:郝建伟 k3s 简介 官方文档:k3s 什么是k3s k3s 是一个轻量级的 Kubernetes 发行版 它针对边缘计算.物联网等场景进行了高度优化. k3s 有以下增强功能: 打包为单个二进 ...
- 【计算几何,数学】7.14 T3 @ xdfz
Problem Link 给定 \(n\) 个球和一个点 \(P\),求点 \(P\) 到这些球的交内一点的距离的最小值.保证有解.\(n\le 10^6\). 和最小圆覆盖一个套路.考虑维护一个当前 ...
- 【一个构想】pull方式获取expoter上的数据,如何更加精简?
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu 公众号:一本正经的瞎扯 背景 已知:在prometheus中,每个业务节点通过prometheu ...
- JS 逆向之 Hook,吃着火锅唱着歌,突然就被麻匪劫了!
关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶.JS/安卓逆向等技术干货! 什么是 Hook? Hook 中文译为钩子,Hook 实际上是 Windows 中提供的一种用以 ...
- uni-app 实现下拉刷新功能
我们在运用uni-app开发小程序或h5时,常常需要页面实现下拉刷新功能. 在 js 中定义 onPullDownRefresh 处理函数(和onLoad等生命周期函数同级),监听该页面用户下拉刷新事 ...