首先在网上查找一些检测代码
放入项目运行,用 ida 打开后 F5 得到下面的
__int64 __usercall sub_10001B3F0@<X0>(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, __int64 a9, __int64 a10, __int64 a11, __int64 a12, ...)
{
__int64 v12; // x0
__int64 v13; // x21
int v14; // w20
__int64 v15; // x0
__int64 v16; // x21
int v17; // w22
BOOL v18; // w23
BOOL v19; // w24
BOOL v20; // w25
int v21; // w22
char *v22; // x21
__int64 v23; // x0
__int64 v24; // x20
__int64 result; // x0
__int64 v26; // x0
__int64 v27; // x21
__int64 v28; // x0
__int64 v29; // x22
__int64 v30; // x0
__int64 v31; // x20
__int64 v32; // x0
__int64 v33; // x20
const char *v34; // [xsp+1C0h] [xbp+70h]
va_list va; // [xsp+1C0h] [xbp+70h]
__int64 v36; // [xsp+1C8h] [xbp+78h]
__int64 v37; // [xsp+1D0h] [xbp+80h]
__int64 v38; // [xsp+1D8h] [xbp+88h]
va_list va1; // [xsp+1E0h] [xbp+90h]
va_start(va1, a12);
va_start(va, a12);
v34 = va_arg(va1, const char *);
v36 = va_arg(va1, _QWORD);
v37 = va_arg(va1, _QWORD);
v38 = va_arg(va1, _QWORD);
v12 = ((__int64 (__fastcall *)(void *))sub_104BFCC20)(&OBJC_CLASS___NSFileManager);
v13 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v12);
v14 = sub_104C07D60();
((void (__fastcall *)(__int64))objc_release)(v13);
v15 = ((__int64 (__fastcall *)(void *))sub_104BFCC20)(&OBJC_CLASS___NSFileManager);
v16 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v15);
v17 = sub_104C07D60();
((void (__fastcall *)(__int64))objc_release)(v16);
v18 = stat("/Library/MobileSubstrate/MobileSubstrate.dylib", (struct stat *)va1) == 0;
v19 = stat("/Applications/Cydia.app", (struct stat *)va1) == 0;
v20 = stat("/var/lib/cydia/", (struct stat *)va1) == 0;
v21 = (stat("/var/cache/apt", (struct stat *)va1) == 0 || v20 || v19 || v18) | v17 | v14;
if ( dladdr(&_stat, (Dl_info *)va) )
v21 |= strcmp(v34, "/usr/lib/system/libsystem_kernel.dylib") != 0;
v22 = getenv("DYLD_INSERT_LIBRARIES");
v23 = ((__int64 (__fastcall *)(void *))sub_104C831E0)(&unk_1063357B0);
v24 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v23);
if ( v22 || v21 )
{
sub_104C65B80();
((void (__fastcall *)(__int64))objc_release)(v24);
v26 = ((__int64 (__fastcall *)(void *))sub_104C2B780)(&unk_1063457C8);
v27 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v26);
v28 = sub_104C031E0();
v29 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v28);
v30 = ((__int64 (__fastcall *)(void *))sub_104C8B4A0)(&OBJC_CLASS___NSString);
v31 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v30);
((void (__fastcall *)(void *))sub_104C96DA0)(&unk_106361810);
((void (__fastcall *)(__int64))objc_release)(v31);
((void (__fastcall *)(__int64))objc_release)(v29);
((void (__fastcall *)(__int64))objc_release)(v27);
v32 = ((__int64 (__fastcall *)(void *))sub_104BDFEA0)(&unk_10633F200);
v33 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v32);
((void (__fastcall *)(void *))sub_104C86300)(&unk_10633F250);
result = ((__int64 (__fastcall *)(__int64))objc_release)(v33);
}
else
{
sub_104C05A80();
((void (__fastcall *)(__int64))objc_release)(v24);
result = ((__int64 (__fastcall *)(void *))sub_104BE4C00)(&OBJC_CLASS___UIView);
}
return result;
}
用 frida hook
frida-trace -UF -i "stat" -f xxx
frida-trace -UF -i "dladdr" -f xxxx
log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
hook stat
/*
* Auto-generated by Frida. Please modify to match the signature of stat.
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/
{
/**
* Called synchronously when about to call stat.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
log(`stat(fildes=${args[0]}, buf=${args[1]})`);
log(`stat(fildes=${(args[0].readUtf8String())}]`);
this.args0 = args[0]; // 入参
this.args2 = args[1]; // 返回值指针
},
/**
* Called synchronously when about to return from stat.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
log(`before:=${retval}`);
var newstr = this.args0 .readUtf8String();//oldNSStr.toString();
if(newstr.search("Cydia")>0
|| newstr.search("MobileSubstrate")>0
|| newstr.search("private---")>0
|| newstr.search("cydia")>0
|| newstr.search("Applications")>0
|| newstr.search("apt")>0
){
log("=========checkJB=hook===========" );
//var str = ObjC.classes.NSString.stringWithString_('{"ret":0,"msg":null,"data":{"c":3,"t":6,"w":60,"fc":1}}'); // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
//args[2] = str;
retval.replace(0xf1) // 修改返回值 0xffffffffffffffff
log(`before:=${retval}`);
log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
}
}
}
hook md5
frida-trace -UF -i “CC_MD5” -f xxxxxxx.xxx.xxxx
/*
* Auto-generated by Frida. Please modify to match the signature of CC_MD5.
* This stub is currently auto-generated from manpages when available.
*
* For full API reference, see: https://frida.re/docs/javascript-api/
*/
{
/**
* Called synchronously when about to call CC_MD5.
*
* @this {object} - Object allowing you to store state for use in onLeave.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {array} args - Function arguments represented as an array of NativePointer objects.
* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
* @param {object} state - Object allowing you to keep state across function calls.
* Only one JavaScript function will execute at a time, so do not worry about race-conditions.
* However, do not use this to store function arguments across onEnter/onLeave, but instead
* use "this" which is an object for keeping state local to an invocation.
*/
onEnter(log, args, state) {
log('CC_MD5()');
this.args0 = args[0]; // 入参
this.args2 = args[2]; // 返回值指针
},
/**
* Called synchronously when about to return from CC_MD5.
*
* See onEnter for details.
*
* @this {object} - Object allowing you to access state stored in onEnter.
* @param {function} log - Call this function with a string to be presented to the user.
* @param {NativePointer} retval - Return value represented as a NativePointer object.
* @param {object} state - Object allowing you to keep state across function calls.
*/
onLeave(log, retval, state) {
var ByteArray = Memory.readByteArray(this.args2, 16);
var uint8Array = new Uint8Array(ByteArray);
var str = "";
for(var i = 0; i < uint8Array.length; i++) {
var hextemp = (uint8Array[i].toString(16))
if(hextemp.length == 1){
hextemp = "0" + hextemp
}
str += hextemp;
}
log(`CC_MD5(${this.args0.readUtf8String()})`); // 入参
log(`CC_MD5()=${str}=`);
}
}
fishhook
rebind_symbols((struct rebinding[1]){{"stat", my_stat, (void *)&orig_stat}}, 1);
rebind_symbols((struct rebinding[1]){{"strcmp", my_strcmp, (void *)&orig_strcmp}}, 1);
//***********************abort********************************
//void abort(void) __dead2;
void abort_hook(void) {
}
static void (*abort_old)(void);
//int stat(const char *, struct stat *) __DARWIN_INODE64(stat);
static int (*orig_stat)(const char *age1, struct stat * age2) ;
static int my_stat(const char *age1, struct stat *age2){
//NSLog(@"[orig_stat =================]");
printf("[orig_stat =hook================]\n my_stat age1=%s ,Cydia=%s\n ",age1,strstr(age1, "Cydia"));
int isfind = 0;
if(strstr(age1, "Cydia") != NULL){
isfind = 1;
}else if (strstr(age1, "cydia") != NULL){
isfind = 1;
}else if (strstr(age1, "MobileSubstrate") != NULL){
isfind = 1;
}else if (strstr(age1, "Applications") != NULL){
isfind = 1;
}else if (strstr(age1, "apt") != NULL){
isfind = 1;
}
if(isfind == 1){
NSLog(@" ========hook=stat===%s\n ",age1);
return 1;//返回不存在
}
return orig_stat(age1,age2);
}
//strcmp
//如果返回值 < 0,则表示 str1 小于 str2。
//如果返回值 > 0,则表示 str2 小于 str1。
//如果返回值 = 0,则表示 str1 等于 str2。
//int strcmp(const char *__s1, const char *__s2);
static int (*orig_strcmp)(const char *__s1, const char *__s2);
static int my_strcmp(const char *__s1, const char *__s2){
if(strstr(__s2, "libsystem_kernel") != NULL){
NSLog(@" ========hook=strcmp===%s %s\n ",__s1,__s2);
return 0;//返回相等
}
return orig_strcmp(__s1,__s2);
}
下面是网上找的源码
//这里都是一些越狱后的手机带的一些框架和工具,未越狱的手机是装不上的。
- (void)isOk0 {
NSString *cydiaPath = @"/Applications/Cydia.app";
NSString *aptPath = @"/private/var/lib/apt/";
NSString *applications = @"/User/Applications/";
NSString *Mobile = @"/Library/MobileSubstrate/MobileSubstrate.dylib";
NSString *bash = @"/bin/bash";
NSString *sshd =@"/usr/sbin/sshd";
NSString *sd = @"/etc/apt";
if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
exit(0);
}
if([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
exit(0);
}
if([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:applications]){
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:Mobile]){
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:bash]){
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:sshd]){
exit(0);
}
if ([[NSFileManager defaultManager] fileExistsAtPath:sd]){
exit(0);
}
}
- (void)isOK1 {
//可能存在hook了NSFileManager方法,此处用底层C stat去检测
// /Library/MobileSubstrate/MobileSubstrate.dylib 最重要的越狱文件,几乎所有的越狱机都会安装MobileSubstrate
// /Applications/Cydia.app/ /var/lib/cydia/绝大多数越狱机都会安装
struct stat stat_info;
if (0 == stat("/Library/MobileSubstrate/MobileSubstrate.dylib", &stat_info)) {
exit(0);
}
if (0 == stat("/Applications/Cydia.app", &stat_info)) {
exit(0);
}
if (0 == stat("/var/lib/cydia/", &stat_info)) {
exit(0);
}
if (0 == stat("/var/cache/apt", &stat_info)) {
exit(0);
}
if (0 == stat("/var/lib/apt", &stat_info)) {
exit(0);
}
if (0 == stat("/etc/apt", &stat_info)) {
exit(0);
}
if (0 == stat("/bin/bash", &stat_info)) {
exit(0);
}
if (0 == stat("/bin/sh", &stat_info)) {
exit(0);
}
if (0 == stat("/usr/sbin/sshd", &stat_info)) {
exit(0);
}
if (0 == stat("/usr/libexec/ssh-keysign", &stat_info)) {
exit(0);
}
if (0 == stat("/etc/ssh/sshd_config", &stat_info)) {
exit(0);
}
}
//strcmp
//如果返回值 < 0,则表示 str1 小于 str2。
//如果返回值 > 0,则表示 str2 小于 str1。
//如果返回值 = 0,则表示 str1 等于 str2。
- (void)isOK2 {
//可能存在stat也被hook了,可以看stat是不是出自系统库,有没有被攻击者换掉
//这种情况出现的可能性很小
int ret;
Dl_info dylib_info;
int (*func_stat)(const char *,struct stat *) = stat;
if ((ret = dladdr(&func_stat, &dylib_info))) {
NSLog(@"lib:%s",dylib_info.dli_fname); //如果不是系统库,肯定被攻击了
if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) { //不相等,肯定被攻击了,相等为0
exit(0);
}
}
}
- (void)isOK3 {
//列出所有已链接的动态库:
//通常情况下,会包含越狱机的输出结果会包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib 。
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count; ++i) {
NSString *name = [[NSString alloc]initWithUTF8String:_dyld_get_image_name(i)];
if ([name containsString:@"Library/MobileSubstrate/MobileSubstrate.dylib"]) {
exit(0);
}
}
}
- (void)isOK4 {
//如果攻击者给MobileSubstrate改名,但是原理都是通过DYLD_INSERT_LIBRARIES注入动态库
//那么可以,检测当前程序运行的环境变量
char *env = getenv("DYLD_INSERT_LIBRARIES");
if (env != NULL) {
exit(0);
}
}
//对于这些函数,不建议单独写方法,容易被hook掉,所以最好是写在不能被hook的函数里,比如application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions。。。
//谁TM会hook程序的初始化函数。。
接下来我将给各位同学划分一张学习计划表!
学习计划
那么问题又来了,作为萌新小白,我应该先学什么,再学什么?
既然你都问的这么直白了,我就告诉你,零基础应该从什么开始学起:
阶段一:初级网络安全工程师
接下来我将给大家安排一个为期1个月的网络安全初级计划,当你学完后,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web渗透、安全服务、安全分析等岗位;其中,如果你等保模块学的好,还可以从事等保工程师。
综合薪资区间6k~15k
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(1周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(1周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(1周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
那么,到此为止,已经耗时1个月左右。你已经成功成为了一名“脚本小子”。那么你还想接着往下探索吗?
阶段二:中级or高级网络安全工程师(看自己能力)
综合薪资区间15k~30k
7、脚本编程学习(4周)
在网络安全领域。是否具备编程能力是“脚本小子”和真正网络安全工程师的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力。
零基础入门的同学,我建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习
搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP,IDE强烈推荐Sublime;
Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,没必要看完
用Python编写漏洞的exp,然后写一个简单的网络爬虫
PHP基本语法学习并书写一个简单的博客系统
熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选)
了解Bootstrap的布局或者CSS。
阶段三:顶级网络安全工程师
如果你对网络安全入门感兴趣,那么你需要的话可以点击这里👉网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!
学习资料分享
当然,只给予计划不给予学习资料的行为无异于耍流氓,这里给大家整理了一份【282G】的网络安全工程师从入门到精通的学习资料包,可点击下方二维码链接领取哦。