前言

昨天结束的比赛,体验不错,Reverse拿了6个一血,也把Reverse的题目AK了,记录下。

文章目录

  • hard
  • Baby_upx
  • Baby_pp
  • baby-maze
  • baby_and
  • baby_anti
  • crypt
  • flag

hard

直接拖进IDA进行分析,先查找字符串


直接发现flag:

HECTF{HElLo_RRRRe}

Baby_upx

根据题目提示,估计是加了upx壳,查壳:


果然加了upx壳,首先尝试用工具脱壳,发现脱壳失败,直接使用esp定律,手动dump下来,拖进ida分析:

先是检验了输入的格式前面是不是HECTF,然后将HECTF这五个字符与括号里的值与进行异或加密,最后与v4中的值进行比较,这里采用了rand()函数,但是没设置种子,所以是伪随机,直接写脚本解:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <Windows.h>
using namespace std;VOID GetFlag()
{unsigned int v4[] = {0x7D2A2B17,0x72A211A,0x1010197D,0x40B1E15,0x42429};char key[] = "HECTF";char *res = (char*)v4;char flag[30] = { 0 };memset(flag, 0, 30);unsigned char middle = 0;int index = 0;for (int i = 0; i <20; i++) {index = (i ^ (rand() + 10086)) % 5;flag[i] = res[i] ^ key[index];}printf("%s\r\n", flag);}
int main(int argc, char *argv[], char *envp[])
{GetFlag();system("pause");return 0;
}

结果:

套上HECTF,得到flag:

HECTF{Thi5_iiS5_UUPX_LalAC}

Baby_pp

拖进IDA,发现了一些奇怪字符:


百度一下,怀疑是用Pyinstaller打包的,那么就是py程序


尝试使用pyinstxtractor和uncompyle6进行反编译,得到源码:

import random
ens = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'
def encode(s, nuum):step = len(s) // nuumens = ''for i in range(step):print(s[i::step])ens += s[i::step]else:return ensdef main():random.seed(10085)u_input = input(': ')t = ''for i in u_input:t += '%02x' % (ord(i) ^ random.randint(0, 127))else:eni = encode(t, 6)if eni == ens:print('Success!')else:print('Failed!')print(t)
if __name__ == '__main__':main()

发现是先将字符串进行异或加密,当然这里种子设置的是固定的,所以rand()也是伪随机,然后打乱字符串的顺序,直接写脚本反向求解一下:

import random
import libnum
ens = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'
def decode(eni,num):random.seed(10085)step=len(eni)//6dec=['1']*108total=0for i in range(step):for j in range(num):dec[j*step+i]=eni[total]total+=1dec=''.join(dec)print(dec)flag=''for i in range(0,len(dec),2):s=dec[i:i+2]middle=int(s,16)flag+=chr(middle^random.randint(0, 127))print(flag)
if __name__ == '__main__':#6是通过加密过程算出来的 加密的时候是每6位为一组decode(ens,6)

结果:

得到一串接近flag的flag,要求我们解密里面的字符串,观察发现里面的字符串只有01248五个数字组成,直接百度:

发现是云影密码,直接拿来用,最终脚本:

import random
import libnum
ens = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'
def decode(eni,num):random.seed(10085)step=len(eni)//6dec=['1']*len(eni)total=0for i in range(step):for j in range(num):dec[j*step+i]=eni[total]total+=1dec=''.join(dec)print(dec)flag=''for i in range(0,len(dec),2):s=dec[i:i+2]middle=int(s,16)flag+=chr(middle^random.randint(0, 127))print(flag)
#云影密码 只有01248这5个数字
def decode_01248(c):dic = [chr(i) for i in range(ord("A"), ord("Z") + 1)]flag = []c2 = [i for i in c.split("0")]for i in c2:c3 = 0for j in i:c3 += int(j)flag.append(dic[c3 - 1])return ''.join(flag)if __name__ == '__main__':#6是通过加密过程算出来的 加密的时候是每6位为一组decode(ens,6)eni="80410840840842108808881088408084210842"print("HECTF{"+decode_01248(eni)+"}")

得到flag:

HECTF{HELLOPYTHON}

baby-maze

题目标题提示,是关于迷宫的题目,拖进ida分析,找到main函数:


发现无法f5,怀疑加了花指令:

往下看发现确实加了花指令,这里就是jnz和jz两个构成绝对跳转,nop掉一个然后一个改成jmp,手动去一下花指令,这里贴两张修改后的图:


修改完后,f5查看伪代码:

发现可疑数据,和类似上下左右走路的判断,往下看.

会从v6里面取值,怀疑v6存储的就是地图,v6是一个数组,那么就是一个三维的地图,根据上面知道总共有6层,然后是通过dword_4033E4去取某层地图,说明控制的是Z坐标,dword_4033E0啥都没有操作,只是简单的加,说明控制的是x坐标,dword_4033E8乘了一个数,说明控制的是y坐标,继续往下看:

可以发现地图中值为2的就是终点,值为1就是路,值为0就是墙,那么就可以写脚本打印地图了:

maze1=[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
maze2=[0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00]
maze3=[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,0x00, 0x00, 0x01, 0x01, 0x00, 0x00]
maze4=[0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00,0x00, 0x00]
maze5=[0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]
maze6=[ 0x02, 0x00, 0x00]for i in range(len(maze1)):if(maze1[i]==1):print("O",end="")else:print("X",end="")if((i+1)%6==0):print("")print("------------------------")for i in range(len(maze2)):if (maze2[i] == 1):print("O", end="")else:print("X", end="")if ((i + 1) % 5 == 0):print("")print("------------------------")for i in range(len(maze3)):if (maze3[i] == 1):print("O", end="")else:print("X", end="")if ((i + 1) % 4 == 0):print("")print("------------------------")for i in range(len(maze4)):if (maze4[i] == 1):print("O", end="")else:print("X", end="")if ((i + 1) % 3 == 0):print("")print("------------------------")for i in range(len(maze5)):if (maze5[i] == 1):print("O", end="")else:print("X", end="")if ((i + 1) % 2 == 0):print("")print("------------------------")for i in range(len(maze6)):if (maze6[i] == 1):print("O", end="")elif(maze6[i] == 2):print("*", end="")else:print("X", end="")

结果:

这里X代表不能走O代表能走,*代表终点。然后根据前面的swtich case来手动走一下迷宫:

得到flag:

HECTF{o....^oo0~0o^^o.^.O^.o^}

baby_and

发现是apk,使用jadx看一下:


发现将输入的值进行base64解码三次,然后发送给别的函数进行处理:

判断解密后的长度是不是4,如果是4再将值取名为key,然后送到别的函数进行处理:

先获取前面传过来的key,然后读取了JFIF.jpg的二进制,将图片的二进制与key进行异或运算,得到新的byte然后将这个byte转化一下,显示成图片,这里怀疑JFIF.jpg这张图片是经过加密的,这里就是一个解密操作,解密成正常的图片,将apk的后缀改成.zip,将JFIF.jpg提取出来,发现:

发现文件头格式不正确,所以我们得将这张图片进行解密,先通过jpg的文件头和文件尾,算出key,然后解密整张图片,写脚本:

with open("JFIF.jpg","rb") as f:imageBytes=f.read()
#jpg文件头 文件尾
res=[0xFF,0xD8,0xFF,0xD9]
key=[1]*4
bytes_list=list(imageBytes)key[0]=res[0]^bytes_list[0]
key[1]=res[1]^bytes_list[1]
key[2]=res[2]^bytes_list[-2]
key[3]=res[3]^bytes_list[-1]for i in key:print(chr(i),end="")
print("")print(bytes_list)
for i in range(len(imageBytes)):bytes_list[i]=key[i%4]^bytes_list[i]imageBytes=bytes(bytes_list)#HECTF{He1l0_Android^_^}
with open("newJFIF.jpg","wb") as f:f.write(imageBytes)

得到一张图片:

得到flag:

HECTF{He1l0_Android^_^}

baby_anti

拖进IDA,找到main函数:


发现main函数无法f5,往下看发现加了花指令,跟baby_maze加的花指令类似,手动去下花指令,贴两张修改后的图:


f5查看伪代码:


先是规定了输入的长度,然后判断了下flag的格式,然后将我们的输入作了转化,且规定了输入的字符只能是数组和abcdef,往下分析:

经过动态调试发现,取出第i+1个转化后的值当作高位,取出第i个转化后的值当作低位合成一个byte类型的值,最后与v14进行比较,而v14的值前面赋值了:

然后写脚本得到flag了,先是通过v14得到转化后的值,再通过判断转化后的值是否小于0xA来判断属于哪个区间,由于求余的关系,求余前面的值不确定,采用爆破的方式获取,最终脚本:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <Windows.h>
using namespace std;
VOID GetFlag_Anti()
{char key[] = "Hel10_aN7i_Re";unsigned char res[26] = { 0 };int total = 0;for (int i = 0; i < 13; i++) {printf("%x\r\n", key[i]);res[total++] = key[i] >> 4;res[total++] = key[i] & 0xF;}char flag[30] = { 0 };memset(flag, 0, 30);for (int i = 0; i < 26; i++) {if (res[i] >= 10) {for (int j = 97; j <= 102; j++) {if ((j - i - 37) % 6 + 10 == res[i]) {flag[i] = j;break;}}}else {for (int j = 48; j <= 57; j++) {if ((j + i + 52) % 10 == res[i]) {flag[i] = j;break;}}}}printf("HECTF{%s}\r\n", flag);return;}
int main(int argc, char *argv[], char *envp[])
{GetFlag_Anti();system("pause");return 0;}

结果:

得到flag:

HECTF{47422b74515e480b70805c3920}

crypt

拖进IDA分析,找到main函数


先是检验了flag的格式,然后通过“-”字符取到括号里的每一段内容,这里只有当v5为偶数时才会进行加密,
往下看:

将加密后的结果值再进行加密,然后和一串字符串进行比较,这串字符看着像base64,查看一下sub_400A72:

发现就是base64的特征,查看一下base64的表:

发现表换掉了,那么就是将base64换表,我们解密一下:

import base64string1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s="7id81DpecpDeES8frwU4Qa=="
print(len(s))a=base64.b64decode(s.translate(str.maketrans(string1,string2)))a=list(a)for i in a:#print(chr(i))print(hex(i),end=",")

得到:

0x84,0x80,0xe2,0x6e,0x73,0xc4,0x8,0xf9,0xc4,0xa3,0x68,0x85,0x45,0x6e,0x1e,0xd0

这串就是前面一次加密后的正确的结果值,再回头看一下:

这里是当v5为偶数时进行加密,而且是将&v7[v5-2]作为参数传递进去的,而这个v7数组进入加密之前就是我们输入的值,分析下sub_4008A4:

可以发现是两两为一组进行加密的,v5就是前一个值,v6就是后一个值,进行加密之后传出去,通过dowrd_602108和dword_60210c进行赋值。这里是累加上去,那么我们逆向的时候就是将上面base64解密得到的结果值,累减过去还原他,写脚本:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <Windows.h>
using namespace std;
VOID GetFlag_Crypt()
{unsigned char a3[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/";unsigned char encode[] = {0x84,0x80,0xe2,0x6e,0x73,0xc4,0x8,0xf9,0xc4,0xa3,0x68,0x85,0x45,0x6e,0x1e,0xd0};char input[] = "1234-5678-abcd-efgh";unsigned int dEncode[] = {0x6EE28084,0xF908C473,0x8568A3C4,0xD01E6E45};unsigned int flag[4] = { 0 };unsigned int v6 = 0;unsigned int v5 = 0;unsigned int middle = 0;unsigned int v7 = 0;int v8 = 0;//将v7的值还原的最后的情况for (int i = 0; i < 32; i++) {v7 -= 0x779EFF7A;}unsigned int end = v7;for (int i = 0; i < 2; i++) {v7 = end;v6=dEncode[i*2+1];v5=dEncode[i*2];for (int j = 0; j < 32; j++) {v8 = *(DWORD*)(4 * ((v7 >> 11) & 3) + a3);middle = (v5 + ((v5 >> 5) ^ (v5 * 16))) ^ (v7+v8);v6 = v6 - middle;v7 += 0x779EFF7A;middle = (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (*(DWORD *)(4 * (v7 & 3) + a3) + v7);v5 = v5 - middle;}flag[i * 2 + 1] = v6;flag[i * 2] = v5;}char *Cflag = (char*)flag;printf("HECTF{");for (int i = 0; i <16; i++) {printf("%c", Cflag[i]);if ((i + 1) % 4 == 0 && i!=15) {printf("-");}}printf("}");}
int main(int argc, char *argv[], char *envp[])
{GetFlag_Crypt();system("pause");return 0;}

结果:

发现不对劲,是乱码,怀疑是脚本写错了,经过排查,没有问题,所以去利用ida远程调试了下加密函数,可能存在猫腻:

发现return后跳到了一个奇怪的地方,f5查看一下:

发现这里会调用一个函数,跟进去看下:

发现会将我们前面的加密的结果再进行一次异或加密,这里也是固定了随机数种子,所以是伪随机,且是linux下c产生的随机数,因为我本机环境是windows懒得去虚拟机下写c,直接手动提取到随机产生的值:

0x3e6,0x103

因此原来的脚本需要改下,要先将结果值进行异或,再进行还原,最终脚本:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <Windows.h>
using namespace std;
VOID GetFlag_Crypt()
{unsigned char a3[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/";unsigned char encode[] = {0x84,0x80,0xe2,0x6e,0x73,0xc4,0x8,0xf9,0xc4,0xa3,0x68,0x85,0x45,0x6e,0x1e,0xd0};char input[] = "1234-5678-abcd-efgh";unsigned int dEncode[] = {0x6EE28084,0xF908C473,0x8568A3C4,0xD01E6E45};unsigned int flag[4] = { 0 };unsigned int v6 = 0;unsigned int v5 = 0;unsigned int middle = 0;unsigned int v7 = 0;int v8 = 0;for (int i = 0; i < 32; i++) {v7 -= 0x779EFF7A;}unsigned int end = v7;for (int i = 0; i < 2; i++) {v7 = end;//去linux下拿到随机数//srand(0x2710)v6 = dEncode[i * 2 + 1] ^ 0x3e6;v5 = dEncode[i * 2] ^ 0x103;for (int j = 0; j < 32; j++) {v8 = *(DWORD*)(4 * ((v7 >> 11) & 3) + a3);middle = (v5 + ((v5 >> 5) ^ (v5 * 16))) ^ (v7+v8);v6 = v6 - middle;v7 += 0x779EFF7A;middle = (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (*(DWORD *)(4 * (v7 & 3) + a3) + v7);v5 = v5 - middle;}flag[i * 2 + 1] = v6;flag[i * 2] = v5;}char *Cflag = (char*)flag;printf("HECTF{");for (int i = 0; i <16; i++) {printf("%c", Cflag[i]);if ((i + 1) % 4 == 0 && i!=15) {printf("-");}}printf("}");}
int main(int argc, char *argv[], char *envp[])
{GetFlag_Crypt();system("pause");return 0;}

得到flag:

HECTF{1024-2048-abcd-hhhh}

flag

拖进IDA分析


发现没有任何符号,然后查看字符串

发现有很多.go字符,怀疑是golang写的,通过查资料,发现有一款IDA插件,IDAGolangHelper,可以进行符号识别,使用一下:

发现符号都识别出来了,然后也找到了主函数:

分析一下:

验证了下flag的格式,然后将输入的flag的每一个字符通过0扩展成四个字节存入.

下面就是加密函数加密很多次,不过这个加密类似前面crypt的加密,可以从后面反推回去:

验证函数就是这个main_flag,进去看一下:

就是将加密后的结果值,与上面那些值进行比较。我们再回去看一下:

这个v29算的有点麻烦,经过ida远程调试发现最后的v30等于v28+1,当v28=29时,v30=0,然后这里一些DWORD1,DWORD2等不认识的转化:





经过ida远程调试发现了取值关系,这里还需要一个v55的值,v55的值在最开头赋值了:

因此将验证函数的结果值作为加密后的值进行反推回去,写脚本:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <Windows.h>
using namespace std;
VOID GetFlag_GoLang()
{unsigned int res[] = {0x67185A11,0xE98651DC,0x354A7497,0x104A33B2,0x4B0D80A6,0x7B7DAD7A,0xEEAB3824,0xFC48315E,0x31AAF1C5,0x577EE036,0x65938F6C,0xDB52C493,0xA20EACE0,0xCC54C27D,0x54ECC3C1,0xF7F51FA6,0xBF187DA8,0x4F723FB1,0x0F936A37,0x466E0D5D,0x42BBA543,0x707D816C,0xEA694ED4,0xA4C6D06F,0x266E4F35,0x3246607F,0xD91B6BFD,0x7933B9A4,0x1185EED8,0xE2E4347D};int v22=0;ULONG64 v21 = 0;ULONG64 v26 = 0;ULONG64 v25 = 0;ULONG64 v30 = 0;ULONG64 v29 = 0;DWORD dv55[4] = {0x64B71598,0xD5FB3BED,0x1185971C,0x6F61074};//还原v22最后的值for (int i = 0; i < 31; i++) {v22 += 0xEAE5AD5;}unsigned int flag[30] = { 0 };unsigned int middle = 0;unsigned int v23 = 0;for (int i = 0; i < 32; i++) {//反推回去还原for (int j = 29; j >= 0; j--) {if (j == 29) {res[0] -= (res[29] + v22 + 0xEAE5AD5) ^ (dv55[2] + 16 * res[29]) ^ (dv55[3] + (res[29] >> 5));res[29] = res[29]-((v22 + res[0] + 0xEAE5AD5) ^ (dv55[0] + 16 * res[0]) ^ (dv55[1] + (res[0] >> 5)));}else {res[j+1]-= (res[j] + v22 + 0xEAE5AD5) ^ (dv55[2] + 16 * res[j]) ^ (dv55[3] + (res[j] >> 5));res[j]= res[j] - ((v22 + res[j+1] + 0xEAE5AD5) ^ (dv55[0] + 16 * res[j+1]) ^ (dv55[1] + (res[j+1] >> 5)));}}v22 -= 0xEAE5AD5;}for (int i = 0; i < 30; i++) {printf("%c", res[i]);}}
int main(int argc, char *argv[], char *envp[])
{GetFlag_GoLang();system("pause");return 0;}

结果:

得到flag:

HECTF{Lets_g0_t0_dr1nk_tea!!!}

HECTF2021 Reverse wp相关推荐

  1. tqlctf reverse wp: Tale of the Arrow quantum

    Tale of the Arrow 题目给了源码, 把输入转成二进制串, 每一位都会打出三个数字, 数字正确和错误可能各一半, 但是其中有一个一定是正确的. 因此利用flag是可见字符最高位必为0 以 ...

  2. 攻防世界 Reverse进阶区 BABYRE WP

    IDA下得到反汇编代码 显然,对于judge这个常量先与或处理,而后读取字符串s,判断s长度是否为14: 接下来这个judge(s)让我看不懂了,judge不是个数组吗,怎么可以这么使用? <关 ...

  3. [WRECKCTF 2022] crypto,reverse,pwn部分WP

    国庆两天,一个比较容易的比赛.会的题不少.感觉到自信了. 目录 国庆两天,一个比较容易的比赛.会的题不少.感觉到自信了. crypto spin baby-rsa mtp prime token rs ...

  4. 2018.11.4 东华杯(骇极) REVERSE What's it wp

    What 打开先要求输入luck string,拖进ida看,输入的必须是长度为6的英文小写.之后对输入的数据取md5,然后遍历生成的MD5串,统计其中0的个数v15和下标总和v14,当满足10*v1 ...

  5. 安恒西湖论剑周周练Reverse刮开有奖WP

    题目信息: 这是一个赌博程序,快去赚钱吧!!!!!!!!!!!!!!!!!!!!!!!!!!!(在编辑框中的输入值,即为flag,提交即可) 无壳无花,IDA 可以直接看到具体过程 关键函数就是这个 ...

  6. HECTF2021 WP(部分)

    crypto RSA_e_n 维纳攻击 from RSAwienerHacker import hack_RSA import binascii,gmpy2 e=0x14b367bf01efd4dc6 ...

  7. 攻防世界 reverse 新手题wp (第二周)

    目录 re1 思路 game 思路 Hello, CTF 思路 simple-unpack 思路 no-strings-attached 思路 re1 题目描述:菜鸡开始学习逆向工程,首先是最简单的题 ...

  8. 接第一篇博客:fw的第二场CTF——HECTF2021 WP

    第一篇博客,第一次参加比赛https://blog.csdn.net/qq_42880719/article/details/110139040就是HECTF 所以这HECTF我非打不可了 想当年,刚 ...

  9. 史上最详细sql注入wp

    文章目录 sql注入wp(史上最详细) 前言 什么是SQL注入? SQL注入的原理 常见的注入方式 常见绕过技巧 常见防控SQL注入的方法 手工查询语句 Basic Challenges Less-1 ...

最新文章

  1. 自制清理电脑里的垃圾软件
  2. dedecms插件开发教程
  3. 层次分解位置编码,让BERT可以处理超长文本
  4. eclipse查看jar包中class的中文注释乱码问题的解决
  5. You must supply a resourceID for a TextView
  6. std::string的resize()与reserve()的区别
  7. 【绿色版】飞鸽传书2011绿色版
  8. 受疫情影响 蔚来整车生产已经暂停
  9. mysql8主从复制集群_rancher 2.X 搭建小型web集群+mysql主从复制
  10. 蓝桥杯十六进制转化为十进制
  11. Pannellum:实例之全景图自动旋转
  12. Luogu1904 天际线
  13. 二、瞰景Smart3D软件安装及授权
  14. JavaScript基础知识总结(6张思维导图)
  15. 用U880做热点 使电脑上网(绑定usb和便携式wlan热点)
  16. linux如何添加打印机,ubuntu系统添加打印机
  17. 【手眼标定】ROS + usb_cam + aruco_ros + easy_handeye_demo
  18. 微信演进的六点思考:微信生态如何演变?如何在其中掘金?
  19. 归一化相关系数NCC
  20. hey-cli初使用

热门文章

  1. 银河护卫队漫威大法好之漫威系列
  2. http状态码有哪些 ,表示了什么
  3. 使用BL0942 计量芯片获取计量数据
  4. CI/CD的利器k8s+docker
  5. 来钱快的3种副业,虽然不起眼,不过很赚钱‍‍‍
  6. 春雨(程序员减压儿歌)
  7. 【毕业设计】python 爬虫与协同过滤的新闻推荐系统
  8. “最后的逆袭”----你可能只缺一份人工智能专家综合手册
  9. 指针的大小与什么有关
  10. fiyme android底层,魅族首批Android 10底层Flyme于今日正式推送