面接試験問題メモ
自己的项目随便吹,不要露馅就行,自信点
代码不用急着写,先定下心来想好思路
还是要看看开发相关的东西,暂时先多看看java
字节
一面(安全与风控 提前批)
- 反调试方法
https://bbs.pediy.com/thread-223460.htm - frida 原理
Frida大致原理是手机端安装一个server程序,然后把手机端的端口转到PC端,PC端写python脚本进行通信,而python脚本中需要hook的代码采用javascript语言。
https://blog.csdn.net/qq_1290259791/article/details/100381831
3. Xposed原理
通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。
- 如何检测Xposed劫持
在
/proc/self/maps
中检测是否存在XposedBridge
- 检测XposedBridge.jar这个文件和de.robv.android.xposed.XposedBridge XposedBridge.jar存放在framework里面,de.robv.android.xposed.XposedBridge是开发xposed框架使用的主要接口。
在这个方法里读取了maps这个文件,在linux内核中,这个文件存储了进程映射了的内存区域和访问权限。在这里我们可以看到这个进程加载了那些文件。
如果进程加载了xposed相关的so库或者jar则表示xposed框架已注入。
- Inlinehook原理
直接修改需要Hook的位置的指令代码,并让其跳转到桩函数中。在桩函数里会处理寄存器信息,并调用自定义的桩函数。处理完桩函数后,跳转到存有原指令的地方并执行,然后再跳转回原来的函数。
- 如果libc.so的read被Inlinehook了,如何检测他被Hook了
Inlinehook只能对内存里的进行hook,所以只要读取系统里的libc.so文件一一比对opcode就可以了。
- IDA添加结构体快捷键
Shift+F9
https://blog.csdn.net/yuqian123455/article/details/82317334
8. tcpdump原理
tcpdump 接收从底层过滤程序上传的分组,并按指定格式打印出来,tcpdump
由两个组件组成,一个是内核组件,负责从网络上捕获分组并可能会过滤;另一个是用户空间组件,负责处理用户界面、格式化显示,以及在内核中完成未完成的过滤。
- 数据包首先到网卡,然后通过软中断的形式触发内核对其处理,放入内存,最后再被应用程序读取。tcpdump是通过调用libpcap的api函数来实现的(获取捕获报文的接口,和捕获报文并将报文交给callback。)。
- monkey原理
Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。
- 如何确认抓到的数据包是哪个进程的
可以根据数据包的端口,查询端口占用进程
(我们项目里没用这个是因为当截取数据包后进行端口占用进程查询时,目标进程很有可能已经释放该端口,或者是新的进程占用了端口,造成查询结果的不准确)
11. https加密方式
https://www.jianshu.com/p/cf2f86bc597a
1、客户端向服务器端索要并验证公钥。 2、双方协商生成"对话密钥"。 3、双方采用"对话密钥"进行加密通信。
其中,前两个阶段,被称为“握手阶段”。
- 编程题: 链表转置
递归、三指针、栈
二面(安全与风控 提前批)
问项目,比较细
- 代理抓流量
我们用真机去抓的流量
- inspeckage能够hook的函数api等
名字 | 属性 |
---|---|
serialization | 进行序列化的文件路径、文件序列化后的十六进制 |
crypto | SecretKeySpec类中想要构造密钥的字节数组以及使用过的加密算法 ;② 使用Cipher类进行加密的原数据和加密后的数据;③Cipher类新缓冲区中的初始化向量(IV);④ IvParameterSpec类中作为IV的字节数组;⑤ SecureRandom类中生成随机数的种子字节数;⑥ Cipher类的转换名称(DES/CBC/PKCS7Padding);⑦ PBEKeySpec类中的密码、salt、迭代计数和将要派生的密钥长度 |
IPC | ①启动的Activity或Activity数组;②启动的Service;③ 发送广播的发送器;④ 接受广播的接收器 |
prefs | ① 从ContextWrapper类中getSharedPreferences获得查询的文件名和操作模式;② 访问的SP文件和请求访问的键key及其对应的值value(单个或集合)(如果没有对应的值返回默认值) |
sqlite | 数据库查询语句 |
filesystem | ① 打开文件进行的操作 ; ② 新建的文件名及路径 |
miscellaneous | ①准备创建URI对象的URI字符串 ;②hook的广告ID |
http | ①创建httpUrlConnection对象的URL ;②想要打开的URI |
- 流量获取的特征
- 平均的包的大小
- 每条流的平均周期
- 包与包之间发送的时间间隔
- 包与包之间接受的时间间隔
- 上行包的比重
- 上行比特率的比重
- 每条流平均发送的比特数
- 流量的构成(TCP的占比)
- 每条流/每秒平均发送/接收的包数/比特数
- 与某个目的IP连接的占比
- 安卓客户端抓流量的缺陷
- 可能被截获服务端的测试报告
- 用户需要root权限
- 仅限于物理特征很大程度会产生误报
- https密钥协商
https://www.easemob.com/news/3706
HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。
证书验证阶段:
①. 浏览器发起 HTTPS 请求。
② 服务端返回 HTTPS 证书(包含公钥)。
③ 客户端验证证书是否合法,如果不合法则提示告警。
数据传输阶段:
①. 当证书验证合法后,在本地生成随机数。
② 通过公钥加密随机数,并把加密后的随机数传输到服务端。
③ 服务端通过私钥对随机数进行解密。
④ 服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输。
- 如何验证证书的合法性
① 浏览器发起 HTTPS 请求时,服务器会返回网站的 SSL 证书。 ②
浏览器需要对证书做以下验证:验证域名、有效期等信息是否正确。证书上都有包含这些信息,比较容易完成验证。 ③
判断证书来源是否合法。每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证;
判断证书是否被篡改。需要与 CA 服务器进行校验; 判断证书是否已吊销。通过 CRL(Certificate Revocation List
证书注销列表)和 OCSP(Online Certificate Status Protocol 在线证书状态协议)实现。
以上任意一步都满足的情况下浏览器才认为证书是合法的。
浏览器需要验证SSL证书的5个方面:
第一,验证浏览器中“受信任的根证书颁发机构”是否存在颁发该SSL证书的机构。
第二,检查证书有没有被证书颁发机构吊销。
第三,验证该网站的SSL证书是否过期。
第四,审核该SSL证书的网站的域名是否与证书中的域名一致。
第五,该网站有没有被列入欺诈网站黑名单。
在经过上述5个方面确认后,才能安全显示该网站,所以部署一个SSL证书对网站安全还是很有必要的!
它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等)
monkey随机生成一个点击屏幕事件,然后选取Android屏幕的一个坐标,对此坐标进行点击操作。当然产生的事件不仅仅局限于点击屏幕,还有滑动屏幕,反转屏幕,点击音量等按键,休眠等等不同的事件。针对不同的事件也有不同的注入方式。
monkey源码中有三种生成事件的方式:默认方式、从网络获取方式、从脚本获取方式。
一面(游戏测开 提前批?)
- tcp和udp的区别
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
- TCP传输单位称为TCP报文段,UDP传输单位称为用户数据报。 TCP对系统资源要求较多,UDP对系统资源要求较少
- UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信
- 为什么TCP是三次握手而不是两次或者四次
两次不可靠四次不高效
- 如果是一次握手的情况:
由于TCP是面向连接的,一次很明显时不可能的,因为客户端发出连接消息后,却没有接收到来自服务端的回应,客户端就无法确定服务端接是否收到了连接请求,当然也就不能确定是否连接成功。- 如果是两次握手的情况:
既然一次客户端接收不到服务端的回应,那就连接两次,接收到回应就说明服务端接收到了连接请求,可以连理连接了。结果并不是这样。如果客户端想建立连接,给服务端发了一个连接请求(SYN),但是由于网络中种种情况,导致没有及时到达服务端,这就导致客户端在很长一段时间中没有收到回复消息(ACK),这时客户端又给服务端发送一个SYN,这次的发送和接收的很顺利,很快就收到了ACK,但是这时之前的SYN终于到了服务端,服务端规规矩矩的为这个SYN申请资源,然后返回ACK。由于之前的SYN已经失效了,所以客户端也不会去理会这个ACK,但是傻乎乎的服务端并不知道这个SYN已经失效了,一直为他委会着资源,这就造成了资源的浪费。- 如果是三次握手的情况:
在两次握手中服务端不知道当前这个SYN是不是有效的,三次握手就很好的解决了这个问题,第三次握手就是客户端给服务端回复第二次握手,这也就是说服务端会等第三次握手的到来,如果第三次握手迟迟不来,服务端就可以识别这个SYN是无效的,就会将他的资源释放了。还有一种情况就是第三次握手由于网络中的种种原因失败了,这时候客户端认为自己已经连接好了,就会给服务端发送数据,服务端由于没有收到第三次握手,就会以RST包对客户端响应,收到RST的的客户端就知道第三次握手没有成功,就会重新连接。在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
- 非对称加密和对称加密的区别
1、加密和解密过程不同
对称加密过程和解密过程使用的同一个密钥,加密过程相当于用原文+密钥可以传输出密文,同时解密过程用密文-密钥可以推导出原文。但非对称加密采用了两个密钥,一般使用公钥进行加密,使用私钥进行解密。2、加密解密速度不同 对称加密解密的速度比较快,适合数据比较长时的使用。非对称加密和解密花费的时间长、速度相对较慢,只适合对少量数据的使用
3、传输的安全性不同
对称加密的过程中无法确保密钥被安全传递,密文在传输过程中是可能被第三方截获的,如果密码本也被第三方截获,则传输的密码信息将被第三方破获,安全性相对较低。
- https的加密方式(见上)
- 动态分析的步骤
- 将IDA目录下的android_server文件push进/data/local下(只要让文件可执行就行)
- 赋予权限chmod 777 /data/local/android_server
- 执行./data/local/android_server
- 输入adb forward tcp:23946 tcp:23946 ,让手机中的23946端口映射到PC本地23946端口,用来IDA和手机通信连接
- 执行adb shell am start –D –n com.example.protectapp/org.isclab.shh.protectapp.MainActivity(包名/入口类 一定要写完整),让需要脱壳的程序在开启入口活动前进入等待调试连接状态。
- 打开IDA找到目标程序的包名,附加程序
(ARM环境:Debugger->Remote ARMLinux/Android debugger
hostname:127.0.0.1 port:23946
Debugger setup Event选项卡中选第3、4、5个
再选择目标进程进行attach(进程号可以用ps命令查))- 对目标函数下断点
- (可有可无)输入 adb forward tcp:8700 jdwp:12876(12876为attach目标进程的pid)
- 输入jdb –connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700 jdb转发运行程序
- 按F9运行程序,进行动态调试和分析
- 动态分析是否要root
- arm传参
ARM架构下,函数参数是通过 r0~r3寄存器传递的;但是如果参数超过四个,就要借助于栈了。
- 返回地址在哪个寄存器
lr寄存器,R14
- 常用的网络收发函数
java : HTTPURLConnection、 X509TrustManager、HTTPsURLConnection
c : https_post
https://blog.csdn.net/marywang56/article/details/78192290
- 大端小端模式的转换
- 方式
将最后8为移动到高八位,倒数第二八位移动到第二高八位,依此移动即可
- 转换时间
intel都是小端,网络上都是大端.
不同的处理器体系可能采用不同的字节序。
- C++内存分配和回收的方式
分配内存时,有三种方式
- 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
- 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
- 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它。
- 函数
分配:
- calloc 函数: void *calloc(unsigned int num, unsigned int size)
按照所给的数据个数和数据类型所占字节数,分配一个 num * size 连续的空间。 calloc申请内存空间后,会自动初始化内存空间为 0,但是malloc不会进行初始化,其内存空间存储的是一些随机数据。- malloc 函数: void *malloc(unsigned int size)
在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。- realloc 函数: void *realloc(void *ptr, unsigned int size)
动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size。
申请的内存空间不会进行初始化。- new是动态分配内存的运算符,自动计算需要分配的空间,在分配类类型的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。
回收:
- delect是回收new的内存运算符
- 游戏的防护需要注意哪些
- 给个协议{int ID; int number} 对他进行测试
- 游戏测试开发的理念
- 编程题:给个只有括号的字符串,看这个字符串是否合法
栈
二面(游戏测开 提前批?)
- 问项目相关,时间最长的项目的主要流程、遇到的困难、以及怎么解决
- DNS劫持是什么,如何避免它
- DNS劫持
定义 : 域名劫持就是在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则直接返回假的IP地址或者什么也不做使得请求失去响应,其效果就是对特定的网址不能访问或访问的是假网址。
- DNS劫持方法
- 利用DNS服务器进行DDOS攻击
- DNS缓存感染
- DNS信息劫持
- DNS重定向
- 如何避免
- 手动指定dns。对于DNS劫持,可以采用使用国外免费公用的DNS服务器解决。例如OpenDNS(208.67.222.222)或GoogleDNS(8.8.8.8)。
- 修改路由器密码.(????)
- 互联网公司准备两个以上的域名,一旦黑客进行DNS攻击,用户还可以访问另一个域名。
- 使用httpDNS
https无法防止dns劫持,因为dns劫持发生在你和web 服务器建立连接之前。
- httpDNS和Local DNS(?)
https://www.cnblogs.com/jimmyhe/p/11279762.html
https://www.sohu.com/a/324822469_534345
- HTTPDNS
HTTPDNS不走传统使用UDP的DNS解析,而是自己搭建基于HTTP协议的DNS服务器集群,分布多个地点和多地运营商,当客户端需要DNS解析的时候,就通过HTTP协议进行请求这个服务器集群。到就近的地址。
https://www.jianshu.com/p/15ff2aeb5b5b
功能 | 说明 |
---|---|
防劫持 | 绕过运营商Local DNS,避免域名劫持,让每一次访问都畅通无阻。 |
精准调度 | 基于访问的来源IP,获得最精准的解析结果,让客户端就近接入业务节点 |
0ms解析延迟 | 通过热点域名预解析、缓存DNS解析结果、解析结果懒更新策略等方式实现0解析延迟 |
快速生效 | 避免Local DNS不遵循权威TTL,解析结果长时间无法更新的问题 |
降低解析失败率 | 有效降低无线场景下解析失败的比率 |
- Local DNS
负责执行递归查询的。由各大运行商提供。
本地域名服务器本身不具备权威域名服务器解析域名的功能,它的作用有两个:
- 代替用户设备参与域名查询的迭代过程,帮助获取域名查询结果返回给用户设备;
- 缓存域名查询记录,当其他用户发起相同的域名查询请求时可以直接返回查询结果,可以加快域名查询速度,同时也降低了权威服务器,尤其是根服务器的工作压力。
- java的重写和重载是什么
- 重写
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
- 重载
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
- 重写和重载的区别
重载就是同样的一个方法能够根据输入参数的不同,做出不同的处理
重写就是当子类继承父类的相同方法,输入数据一样,但要做出有别于父类的相应时,要覆盖父类的方法
- java的static关键字的作用
https://www.cnblogs.com/dolphin0520/p/3799052.html
方便在没有创建对象的情况下来进行调用(方法/变量)
- 修饰成员变量和成员方法
- 静态代码块
- 修饰类(只能修饰内部类)
- 静态导包(用来导入类中的静态资源,1.5之后的新特性)
- 在静态方法中调用一个非静态成员是非法的
由于静态方法中可以不通过对象进行调用,因此不能调用其它非静态变量,也不可以访问非静态变量成员
- 编程题:给个随机数组,奇数在前、偶数在后,奇数从大到小排序、偶数从小到大,进行排序
注意自己刷题的时候要从头到尾都自己写一遍,调用自己写的函数
import java.util.*;
public class Test {
public static void main(String[] args) {
int[] a = new int[]{
4,1,2,5,6,3,7,4,9,0,8};
int[] res = new Test().sort(a);
for(int temp : res)
System.out.