frida hook so层、protobuf 数据解析

手机安装 app ,设置代理,然后开始抓包。

发现数据没法解密,查看请求的 url 是 http://lbs.jt.sh.cn:8082/app/rls/monitor,使用 jadx 反编译 app 后搜索这个 url(提示:可以只搜索 url 中一部分,因为请求的 url 可能时好几部分拼接而成的),这里搜索 rls/monitor

 点进去,然后在 右键 ---> 查找用例

再点进去

127 行是 添加 post data,和上面抓包结果可以对应上,所以这部分代码就是需要分析的代码。

查看 com.shjt.map.data.rline.Response,可以看到 Protoc.Response response = Protoc.Response.parseFrom(Native.decode2(bytes));

在查看 decode2 函数,可以看到是 native 类型的函数,是在 so 库中

 

解压 apk 文件,找到 so 库文件 libnative.so ,使用 ida pro 打开,然后搜索 java_ 开头的函数

 点进去,然后按 F5 查看伪代码:

protobuf 语法中文翻译:https://colobu.com/2017/03/16/Protobuf3-language-guide/

Protobuf 正向流程

Protobuf 进阶——使用 Python 操作 Protobuf:https://blog.csdn.net/a464057216/article/details/54932719

proto.exe 编译命令,自动生成 python 程序:protoc --python_out=. addressbook.proto
编译 addressbook.proto 文件,生成 addressbook_pb2.py
利用 proto.exe 反解数据 protoc.exe --decode_raw < D:\a.bin

protoc 命令帮助:

protoc -help
Usage: protoc [OPTION] PROTO_FILES
Parse PROTO_FILES and generate output based on the options given:-IPATH, --proto_path=PATH   Specify the directory in which to search forimports.  May be specified multiple times;directories will be searched in order.  If notgiven, the current working directory is used.If not found in any of the these directories,the --descriptor_set_in descriptors will bechecked for required proto file.--version                   显示版本号-h, --help                  帮助信息--encode=MESSAGE_TYPE       从标准输入读取文本格式信息,然后从标准输出中输出二进制数据,需要指定 PROTO_FILES--deterministic_output      When using --encode, ensure map fields aredeterministically ordered. Note that this orderis not canonical, and changes across builds orreleases of protoc.--decode=MESSAGE_TYPE       从标准输入中读取2进制数据,然后以文本方式输出到标准输出,需要指定 PROTO_FILES--decode_raw                从标准输入中读取任意的protocol数据,然后以 tag/value的格式输出到标准输出,不需要指定 PROTO_FILES --descriptor_set_in=FILES   Specifies a delimited list of FILESeach containing a FileDescriptorSet (aprotocol buffer defined in descriptor.proto).The FileDescriptor for each of the PROTO_FILESprovided will be loaded from theseFileDescriptorSets. If a FileDescriptorappears multiple times, the first occurrencewill be used.-oFILE,                     Writes a FileDescriptorSet (a protocol buffer,--descriptor_set_out=FILE defined in descriptor.proto) containing all ofthe input files to FILE.--include_imports           When using --descriptor_set_out, also includeall dependencies of the input files in theset, so that the set is self-contained.--include_source_info       When using --descriptor_set_out, do not stripSourceCodeInfo from the FileDescriptorProto.This results in vastly larger descriptors thatinclude information about the originallocation of each decl in the source file aswell as surrounding comments.--dependency_out=FILE       Write a dependency output file in the formatexpected by make. This writes the transitiveset of input file paths to FILE--error_format=FORMAT       Set the format in which to print errors.FORMAT may be 'gcc' (the default) or 'msvs'(Microsoft Visual Studio format).--fatal_warnings            Make warnings be fatal (similar to -Werr ingcc). This flag will make protoc returnwith a non-zero exit code if any warningsare generated.--print_free_field_numbers  Print the free field numbers of the messagesdefined in the given proto files. Groups sharethe same field number space with the parentmessage. Extension ranges are counted asoccupied fields numbers.--plugin=EXECUTABLE         Specifies a plugin executable to use.Normally, protoc searches the PATH forplugins, but you may specify additionalexecutables not in the path using this flag.Additionally, EXECUTABLE may be of the formNAME=PATH, in which case the given plugin nameis mapped to the given executable even ifthe executable's own name differs.--cpp_out=OUT_DIR           Generate C++ header and source.--csharp_out=OUT_DIR        Generate C# source file.--java_out=OUT_DIR          Generate Java source file.--js_out=OUT_DIR            Generate JavaScript source.--kotlin_out=OUT_DIR        Generate Kotlin file.--objc_out=OUT_DIR          Generate Objective-C header and source.--php_out=OUT_DIR           Generate PHP source file.--python_out=OUT_DIR        Generate Python source file.--ruby_out=OUT_DIR          Generate Ruby source file.@<filename>                 Read options and filenames from file. If arelative file path is specified, the filewill be searched in the working directory.The --proto_path option will not affect howthis argument file is searched. Content ofthe file will be expanded in the position of@<filename> as in the argument list. Notethat shell expansion is not applied to thecontent of the file (i.e., you cannot usequotes, wildcards, escapes, commands, etc.).Each line corresponds to a single argument,even if it contains spaces.

注意:window Termimal 只能执行 cmd 命令,没法执行 linux 命令,cmder ( https://cmder.net/ ) 即可以执行 cmd 命令,也可以执行 linux 的一些命令,安装 cmder 然后执行反解数据

示例 protobuf 二进制数据:https://api.bilibili.com/x/v2/dm/web/seg.so?type=1&oid=168855206&pid=98919207&segment_index=1

点击后会下载一个 seg.so 的文件,然后执行反解命令:protoc.exe --decode_raw < "seg.so"

注意:因为没有 proto 文件,所以反解数据后,值是对的,但是没有 key,

反解 Protobuf 方法

方法一:还原 .proto 文件:

  •     1.利用 protoc.exe 反解析 protobuf 数据
  •     2.根据反解析出来的数据,还原出 .proto 文件
  •     3.用 protoc.exe 编译 .proto 文件,生成 py 程序
  •     4.用 py 程序可以轻松序列化和反序列化

方法二:利用 blackboxprotobuf 库直接操作 protobuf 数据,不需要还原 .proto 文件

# -*- coding: utf-8 -*-
# @Author  : 佛祖保佑, 永无 bug
# @Date    : 
# @File    : temp.py
# @Software: PyCharm
# @description : XXXimport blackboxprotobufdef main():seg_so = Nonewith open('d:/seg.so', 'rb') as f:seg_so = f.read()msg, typ = blackboxprotobuf.protobuf_to_json(seg_so, message_type=None)print(msg)print(typ)if __name__ == '__main__':main()pass

加解密相关知识:

hook加密类:
各加密类的用法,key iv 明文 密文等是如何获取的,再hook对应的类和方法
AES https://www.cnblogs.com/widgetbox/p/11611201.html
RSA https://blog.csdn.net/qq_22075041/article/details/80698665
DES https://www.jianshu.com/p/bf6b4afaf41e
MD5 SHA等摘要算法 https://blog.csdn.net/baidu_34045013/article/details/80687557
HMAC摘要算法 https://blog.csdn.net/cdzwm/article/details/6973345

android的rsa加密填充方式是RSA时,是NoPadind RSA/ECB/NoPadding,
而标准jdk里填充是RSA时,是指PKCS1填充,RSA/ECB/PKCS1Padding,要注意
RSA加密科普 https://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html 
RSA加密科普 https://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
RSA密钥长度关系 https://cloud.tencent.com/developer/article/1199963
python rsa加密库 https://pycryptodome.readthedocs.io/en/latest/src/examples.html#generate-an-rsa-key
公私钥ASN.1结构 https://blog.csdn.net/wzj_whut/article/details/86477568
ASN.1、PKCS、PEM间的关系 https://blog.csdn.net/qq_39385118/article/details/107510032

AES 加密:一种对称加密,加密和解密时需要:密匙(key)iv加密模式 三个参数,加密时明文需要先做对齐处理,kv 和 iv 有长度规定(AES-128、AES-192和AES-256),明文长度要为16的倍数,否则要给明文后面加0补齐长度。

 可以看到

  • 函数 j_aes_key_setup 用来构造 aes
  • 函数 j_aes_encrypt_cbc 用来解密

所以需要 hook 这两个函数

首先分析 j_aes_key_setup 这个函数,一直追进去,然后找到 export 的函数名,

可以看到函数名为 _Z13aes_key_setupPKhPji,hook 的时候需要 hook 这个函数名,同理可以找到 j_aes_encrypt_cbc hook 时 export 的函数名为 _Z15aes_encrypt_cbcPKhjPhPKjiS0_

frida hook js 代码如下:

Interceptor 使用方法文档:https://frida.re/docs/javascript-api/#interceptor

function printstack() {console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
}function hook_so() {console.log("\r");var Requester = Java.use('com.shjt.map.view.layout.realtime.LineLayout$Requester');Requester.request.implementation = function (p1) {this.request(p1)}var Req = Java.use('com.shjt.map.data.rline.Request');Req.toString.implementation = function (p1) {//send(this.mBuilder.build().toByteArray())var tmp = this.toString()send('11111111:' + tmp)return tmp}var ByteString = Java.use('com.android.okhttp.okio.ByteString')var Native = Java.use('com.shjt.map.tool.Native');Native.decode2.implementation = function (pp) {console.log("str :" + Java.use('java.lang.String').$new(pp));// 因为字节数组中有的转化成字符串也是不可见的,所以转成 16进制console.log("hex :" + ByteString.of(pp).hex());console.log("array :" + JSON.stringify(pp));return this.decode2(pp)}var soBaseAddress = Module.findBaseAddress("libnative.so");if (soBaseAddress) {// 查找 aes_key_setup 函数var aes_key_setup = Module.findExportByName("libnative.so", '_Z13aes_key_setupPKhPji');if (aes_key_setup) {console.log("找到 aes_key_setup")Interceptor.attach(aes_key_setup, {onEnter: function (args) {// console.log("aes_key_setup args 类型" + typeof args);// console.log("aes_key_setup args[0] " + typeof args[0].readByteArray(16) + " " + args[0].readByteArray(16));console.log("aes_key_setup args[0] ", args[0].readByteArray(16));console.log("aes_key_setup args[1] ", args[1].readByteArray(16));console.log("aes_key_setup args[2] ", args[2].toInt32());},onLeave: function (retval) {console.log("aes_key_setup 返回值:" + retval);}})} else {console.log("没找到 aes_key_setup")}// 查找 aes_encrypt_cbc 函数var aes_encrypt_cbc = Module.findExportByName("libnative.so", '_Z15aes_encrypt_cbcPKhjPhPKjiS0_');if (aes_encrypt_cbc) {console.log("找到 aes_encrypt_cbc")Interceptor.attach(aes_encrypt_cbc, {onEnter: function (args) {// console.log("aes_encrypt_cbc args 类型" + typeof args);// console.log("aes_encrypt_cbc args[0] " + typeof args[0].readByteArray(16) + " " + args[0].readByteArray(16));console.log("aes_encrypt_cbc args[0] ", args[0].readByteArray(16));console.log("aes_encrypt_cbc args[1] ", args[1].toInt32());console.log("aes_encrypt_cbc args[2] ", args[2].readByteArray(16));console.log("aes_encrypt_cbc args[3] ", args[3].readByteArray(16));console.log("aes_encrypt_cbc args[4] ", args[4].toInt32());console.log("aes_encrypt_cbc args[5] ", args[5].readByteArray(16));},onLeave: function (retval) {console.log("aes_encrypt_cbc 返回值:" + retval);}})} else {console.log("没找到 aes_encrypt_cbc")}}
}function main() {Java.perform(hook_so);
}setImmediate(main);

j_aes_key_setup((const unsigned __int8 *)v18, (unsigned int *)v15, 128) 函数有三个参数

  • 第一个参数 和 第二个参数都是指针,
  • 第三个参数 是一个 int 整数

j_aes_encrypt_cbc((const unsigned __int8 *)p, v11, v12, (const unsigned int *)v15, 128, (const unsigned __int8 *)v17); 函数有 6 个参数

  • 第一个参数:指针类型
  • 第二个参数:signed int 类型,是个整数
  • 第三个参数:指针类型
  • 第四个参数:指针类型
  • 第五个参数:int 类型,是个整数
  • 第六个参数:指针类型

frida 关于指针的操作:https://frida.re/docs/javascript-api/#nativepointer

frida js 中指针为什么用 readByteArray 来处理???

因为 AES 最终处理时,都是转换成 "字节数组" 来处理的,所以使用 readByteArray 来处理

为什么是读取 16 字节???

因为 AES 长度有规定 ( 128、192、256 ),可以看到 j_aes_key_setup 和 j_aes_encrypt_cbc 函数参数中都有 128,128bit / 8 = 16Byte,所有暂时可以假定是读取 16 字节。

要不就使用 ida pro 动态调试 so ,确定参数的值,这个属于另外技术范畴不在展开。。。

启动 frida-server

查看 apk 包名

 运行 js 脚本进行 hook。执行命令:frida -U -F com.xxx.map -l .\hook_so.js --no-pause

 可以看到 j_aes_key_setup((const unsigned __int8 *)v18, (unsigned int *)v15, 128) 函数有三个参数 

  • v18 里面存的数据是  2f d3 02 8e 14 a4 5d 1f 8b 6e b0 b2 ad b7 ca af
  • v15 里面存的数据是  02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  • 第三个参数 是 128

j_aes_encrypt_cbc((const unsigned __int8 *)p, v11, v12, (const unsigned int *)v15, 128, (const unsigned __int8 *)v17); 函数有 6 个参数

  • p 参数值  0a 27 0a 18 2f 70 72 6f 74 6f 63 2e 52 65 71 75       key值
  • v11 参数值  48
  • v12 参数值  00 00 00 00 20 00 00 00 61 62 6c 65 2d 61 6e 79
  • v15 参数值  8e 02 d3 2f 1f 5d a4 14 b2 b0 6e 8b af ca b7 ad
  • 128
  • v17  75 4c 8f d5 84 fa cf 62 10 37 6b 2b 72 b0 63 e4              iv值

decode2 参数的 16进制数据:

现在 key、iv、16 进制数据都有了,可以尝试下解密:

Python 的 AES 加密与解密:https://www.cnblogs.com/niuu/p/10107212.html

AES 加密方式有五种:ECB, CBC, CTR, CFB, OFB

从安全性角度推荐 CBC 加密方法,下面是 CBC、ECB 两种加密方法的 python 实现

python 在 Windows下使用AES时要安装的是pycryptodome 模块   pip install pycryptodome 

# 先导入所需要的包
pip3 install Crypto
# 再安装pycrypto
pip3 install pycrypto
from Crypto.Cipher import AES  # 就成功了

python 在 Linux下使用AES时要安装的是pycrypto模块   pip install pycrypto 

  • CBC 加密需要一个十六位的 key (密钥) 和 一个十六位 iv(偏移量)
  • ECB 加密不需要 iv

AES CBC 加密的python实现

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex# 如果text不足16位的倍数就用空格补足为16位
def add_to_16(text):if len(text.encode('utf-8')) % 16:add = 16 - (len(text.encode('utf-8')) % 16)else:add = 0text = text + ('\0' * add)return text.encode('utf-8')# 加密函数
def encrypt(text):key = '9999999999999999'.encode('utf-8')mode = AES.MODE_CBCiv = b'qqqqqqqqqqqqqqqq'text = add_to_16(text)cryptos = AES.new(key, mode, iv)cipher_text = cryptos.encrypt(text)# 因为AES加密后的字符串不一定是ascii字符集的,输出保存可能存在问题,所以这里转为16进制字符串return b2a_hex(cipher_text)# 解密后,去掉补足的空格用strip() 去掉
def decrypt(text):key = '9999999999999999'.encode('utf-8')iv = b'qqqqqqqqqqqqqqqq'mode = AES.MODE_CBCcryptos = AES.new(key, mode, iv)plain_text = cryptos.decrypt(a2b_hex(text))return bytes.decode(plain_text).rstrip('\0')if __name__ == '__main__':e = encrypt("hello world")  # 加密d = decrypt(e)  # 解密print("加密:", e)print("解密:", d)

AES ECB 加密的 python 实现

"""
ECB没有偏移量
"""
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hexdef add_to_16(text):if len(text.encode('utf-8')) % 16:add = 16 - (len(text.encode('utf-8')) % 16)else:add = 0text = text + ('\0' * add)return text.encode('utf-8')# 加密函数
def encrypt(text):key = '9999999999999999'.encode('utf-8')mode = AES.MODE_ECBtext = add_to_16(text)cryptos = AES.new(key, mode)cipher_text = cryptos.encrypt(text)return b2a_hex(cipher_text)# 解密后,去掉补足的空格用strip() 去掉
def decrypt(text):key = '9999999999999999'.encode('utf-8')mode = AES.MODE_ECBcryptor = AES.new(key, mode)plain_text = cryptor.decrypt(a2b_hex(text))return bytes.decode(plain_text).rstrip('\0')if __name__ == '__main__':e = encrypt("hello world")  # 加密d = decrypt(e)  # 解密print("加密:", e)print("解密:", d)

测试:

# -*- coding: utf-8 -*-
# @Author  : 佛祖保佑, 永无 bug
# @Date    : 
# @File    : temp.py
# @Software: PyCharm
# @description : XXXimport base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import binasciidef main():# with open('D:\monitor.bin', 'rb') as f:#     c = f.read()key = '2fd3028e14a45d1f8b6eb0b2adb7caaf'iv = '754c8fd584facf6210376b2b72b063e4'aes = AES.new(binascii.a2b_hex(key), AES.MODE_CBC, binascii.a2b_hex(iv))hex_str = '8509209294464b3e84a122800c9419068fa44cb5827e4df3db42212a6054243a55793243b8d6479773d67ab74749611d987ab38c274bf716a2c66a8f233e9683667af7e84119d371b9926abc6f8294b266534ddb25f8ef015a16c60b770d3198'plaintext = aes.decrypt(binascii.a2b_hex(hex_str))print(plaintext)if __name__ == '__main__':main()pass

把上面 key、iv、hex 替换下,然后运行,程序不报错,说明 传递参数正确。

下面就是写代码,请求URL得到 respone 数据,然后解密数据得到 protobuf 格式的二进制数据,再解析 protobuf 数。。。略略略略略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/495101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据技术与应用解读及案例分析(PPT)

来源&#xff1a;网络大数据摘要&#xff1a;大数据是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。大数据就是未来的石油。未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学…

pywin32库 : Python 操作 windows 系统 API

Python 模块虽多&#xff0c;但也不可能满足所有需求。而且&#xff0c;模块为了便于使用&#xff0c;通常都封装过度&#xff0c;有些功能无法灵活使用&#xff0c;必须直接调用Windows API 来实现。要完成这一目标&#xff0c;有两种办法&#xff0c;一种是使用 C 编写 Pytho…

华为秘密作战计划曝光,重注研发AI芯片挑战英伟达,轮值董事长挂帅

雷刚 问耕 发自 凹非寺 量子位 报道 | 公众号 QbitAI摘要&#xff1a;据报道&#xff0c;对于如何把AI引入所有业务&#xff0c;华为内部已经开启了代号为“达芬奇”的作战计划&#xff0c;并且成为华为高层每月一次讨论会的重点议题&#xff0c;也有不少华为高管以“D项目”来…

Python --- ctypes库的使用

ctypes 的官方文档 英文文档&#xff1a;https://docs.python.org/3/library/ctypes.html中文文档&#xff1a;https://docs.python.org/zh-cn/3.10/library/ctypes.html Python--ctypes(数据类型详细踩坑指南&#xff09;&#xff1a;https://zhuanlan.zhihu.com/p/145165873…

机器学习近年来之怪现象

来源&#xff1a;网络大数据人工智能领域的发展离不开学者们的贡献&#xff0c;然而随着研究的进步&#xff0c;越来越多的论文出现了「标题党」、「占坑」、「注水」等现象&#xff0c;暴增的顶会论文接收数量似乎并没有带来更多技术突破。最近&#xff0c;来自卡耐基梅隆大学…

PySide6 : Qt for Python 教程

Qt for Python 教程&#xff1a;https://doc.qt.io/qtforpython/tutorials/index.html 官方文档示例&#xff1a;https://doc.qt.io/qtforpython/examples/index.html Qt for Python 提供了一系列带有演练指南的教程&#xff0c;以帮助新用户入门。 其中一些文档是从 C 移植到…

PySide6 信号、槽

信号与槽的入门应用&#xff08;一&#xff09;&#xff1a;https://blog.csdn.net/jia666666/article/details/81774175 信号与槽的再细分&#xff08;二&#xff09;&#xff1a;https://blog.csdn.net/jia666666/article/details/81774858 信号与槽的高级玩法&#xff08;三…

芯片业又起波澜!博通189亿美元收购遭质疑,股价一度跌近19%

来源&#xff1a;华尔街见闻摘要&#xff1a;如果说博通上次收购高通面临的最大“对手”是特朗普政府&#xff0c;这次收购CA的“对手”可能是华尔街。如果说博通上次收购高通面临的最大“对手”是特朗普政府&#xff0c;这次收购CA的“对手”可能是华尔街。美东时间周三&#…

JavaScript常用技巧专题五

文章目录 一、使用适当的命名和注释来提高代码可读性二、优雅的写条件判断代码2.1、普通的if else2.2、三元运算符2.3、多个if else2.4、switch case2.5、对象写法2.6、Map写法 三、封装条件语句四、函数应该只做一件事五、Object.assign给默认对象赋默认值六、函数参数两个以下…

HTML 页面的生命周期、HTML 事件

From&#xff1a;https://blog.csdn.net/WuLex/article/details/101016936 1、页面生命周期 HTML页面的生命周期有以下三个重要事件&#xff0c;每个事件都有特定的用途 DOMContentLoaded &#xff1a; 浏览器已经完全加载 HTML&#xff0c;DOM 树已经构建完毕&#xff0c;js …

腾讯再次海选AI项目,1500进40,医疗零售机器人成新风向

雷刚 发自 凹非寺 量子位 报道 | 公众号 QbitAI一年一度风向标&#xff0c;腾讯又一次海选AI项目。去年第一期腾讯AI加速器结业后&#xff0c;鹅厂就马不停蹄开启了第二期报名&#xff0c;而且这一次报名企业更多、竞争更激烈、最终录取概率甚至不到3%。第二期AI加速器通过初试…

The Human Touch 将人工智能和机器人用于病人工作的实际和伦理意义

来源&#xff1a;IEEE电气电子工程师学会摘要&#xff1a;我们生活在一个科幻小说可以很快成为科学事实的时代。在一代人的时间里&#xff0c;互联网已经从技术奇迹变成了实用工具&#xff0c;移动电话重新定义了我们的交流方式。我们生活在一个科幻小说可以很快成为科学事实的…

渗透测试 ( 0 ) --- XSS、CSRF、文件上传、文件包含、反序列化漏洞

漏洞数据库&#xff1a;https://www.exploit-db.com/google-hacking-database 1、渗透测试 实用 浏览器插件 chrome、edge 插件&#xff1a;搜索 cookie&#xff0c;安装 cookie editor&#xff0c;打开插件&#xff0c;可以 导出 cookie HackBar &#xff1a;Hackbar是网络安…

专访盛大创始人陈天桥:未来的杀手级应用必将诞生于脑科学

翻译丨于波 校对丨其奇来源丨Medium 神经科技初见陈天桥&#xff0c;他穿着带有花纹的短袖衬衫&#xff0c;休闲款式的蓝色牛仔裤&#xff0c;迷彩色的运动鞋&#xff0c;仿佛是个享受退休生活的人。过去的他可不是这样。1999年&#xff0c;陈天桥创建盛大游戏公司&#xff0c…

动手解决jar转txt软件的一个缺陷

代码&#xff1a; import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReade…

渗透测试 ( 2 ) --- 渗透测试系统、靶机、GoogleHacking、kali工具

操作系统&#xff1a;https://zhuanlan.zhihu.com/p/162865015 1、基于 Windows、Linux、Android 的渗透测试系统 1.1 基于 Linux 的系统 Kali&#xff1a;https://www.kali.org/get-kali/Parrot Security OS&#xff1a;Parrot Securitybackbox&#xff1a;https://www.backbo…

清华发布《中国AI发展报告2018》:中科院系统AI论文产出全球第一

来源&#xff1a;大数据文摘人工智能正成为全球性话题&#xff0c;各国的AI人才争夺战也正愈演愈烈。那么目前&#xff0c;人工智能在中国的发展条件如何&#xff0c;中国距离成为真正的人工智能强国到底还有多远&#xff1f;基于此&#xff0c;7月13日&#xff0c;《中国人工智…

单例模式小记【原创】

中国的历史上很少出现两个皇帝并存的时期&#xff0c;是有&#xff0c;但不多&#xff0c;那我们就认为皇帝是个单例模式&#xff0c;在这个场景中&#xff0c;有皇帝&#xff0c;有大臣&#xff0c;大臣是天天要上朝参见皇帝的&#xff0c;今天参拜的皇帝应该和昨天、前天的一…

渗透测试 ( 3 ) --- Metasploit Framework ( MSF )

白嫖 &#xff1a;https://zhuanlan.zhihu.com/p/449836479&#xff1a;http://t.zoukankan.com/hxlinux-p-15787814.html&#xff1a;https://www.52pojie.cn/thread-1586222-1-1.html Metasploit Pro 英文文档&#xff1a;https://docs.rapid7.com/metasploit/ Metasploit P…

工业4.0进行时:工业机器人为何能够快速爆发?

来源&#xff1a;资本实验室摘要&#xff1a;聚焦前沿科技创新与传统产业升级自George Devol于1961发明第一台可编程工业机器人“Unimate”以来&#xff0c;工业机器人产业已经走过了几十年的历史。到了2000年&#xff0c;全球约有74.25万台工业机器人。其中&#xff0c;超过一…