如何避免字符串混淆加密_iOS-代码混淆加固方案

对于iOS来说,由于系统是封闭的,APP上架需要通过App Store,安全性来说相当高。但是对于大厂和知名APP而言,别人给的安全保障永远没有自己做的来得踏实。所以对于大厂、少部分企业级和金融支付类应用来说加固是相当重要的。
下面是目前几个专业加固大厂提供的加固策略

  • 网易
48c9713dd518add8c4ba00cecd1c9fda.png
  • 网易安全三板斧:
  1. 第一板斧是防静态分析,这里包括字符串加密、符号混淆、代码逻辑混淆和游戏存档加密;

2.第二板斧是防动态调试、反调试和通信安全(数据加密);

  1. 第三板斧是外挂检测、加速挂、内存修改挂和自动任务挂等
  • 爱加密
fcf0911c676d2e0e05a49032e4b3fa61.png
fcf0911c676d2e0e05a49032e4b3fa61.png
  • safengine
be76f444c0f8d4c39e6ae34b9bdbc274.png
  • 几维安全
0fbec13002c5e4e9deaa1276dc3b51e5.png
  • 梆梆安全
46130cfc499d18e93811f6232593aa2d.png

本文将针对以上几点进行实现,对于一些不太容易实现的将会做方向性讨论

  • 字符串加密
  • 代码混淆(方法名,类名,变量名,符号表)
  • 代码逻辑混淆
  • 反调试

字符串加密

对字符串加密的方式目前我所了解到掌握到的最可靠方式就是用脚本将代码中的所有标记需要加密的字符串进行异或转换,这样代码中就不存在明文字符串了。当然第三方的字符串加密不可能这么简单,具体怎么做的我也不太清楚。不过为了增加字符串加密的难度复杂性,我们可以先将字符串用加密工具转换(例如AES、base64等)后的把加字符串放在工程中,并且把解密的钥匙放在工程中,用异或转换,把解密钥匙和加密后的字符串转换,这样就有2层保障,增加了复杂度。

  • 首先 我们创建任意一个工程,在工程中写入下面的代码,并在每句打上断点,再选择Xcode工具栏的Debug --> Debug Workflow --> Always Show Disassembly。这样你就可以在断点处进入汇编模式界面,最后运行程序
/* 加密NSString字符串 */    NSString *str = @"Hello World";    NSLog(@"%@",str);    /* 加密char*字符串 */    char* cStr = "Super Man";    NSLog(@"%s",cStr);
e802750515d0ba8ee70cad385275cfe7.png

你会发现,你的字符串内容暴露在了汇编模式中,这会导致别人在逆向分析你的工程时能看见你的字符串内容,我们一般接口、域名、加解密钥匙串、AppKey、AppId等比较重要的东西会放在客户端用作字符串,这就很容易暴露出来。

  • 步骤1 首先需要在工程代码中进行修改,把下面的宏和decryptConfusionCS,decryptConstString函数放入代码中,用宏包含每个需要转换的字符串。
/* 字符串混淆解密函数,将char[] 形式字符数组和 aa异或运算揭秘 */extern char* decryptConfusionCS(char* string){    char* origin_string = string;    while(*string) {        *string ^= 0xAA;        string++;    }    return origin_string;}/* 解密函数,返回的是NSString类型的 */extern NSString* decryptConstString(char* string){    /* 先执行decryptConfusionString函数解密字符串 */    char* str = decryptConfusionCS(string);    /* 获取字符串的长度 */    unsigned long len = strlen(str);    NSUInteger length = [[NSString stringWithFormat:@"%lu",len] integerValue];     NSString *resultString = [[NSString alloc]initWithBytes:str length:length encoding:NSUTF8StringEncoding];    return resultString;}/* * 使用heyujia_confusion宏控制加密解密 * 当heyujia_confusion宏被定义的时候,执行加密脚本,对字符串进行加密 * 当heyujia_confusion宏被删除或为定义时,执行解密脚本,对字符串解密 */#define heyujia_confusion#ifdef heyujia_confusion/* heyujia_confusion 宏被定义,那么就进行执行解密脚本 *//* confusion_NSSTRING宏的返回结果是NSString 类型的 */#define confusion_NSSTRING(string) decryptConstString(string)/* confusion_CSTRING宏的返回结果是char* 类型的 */#define confusion_CSTRING(string) decryptConfusionCS(string)#else/* heyujia_confusion 宏没有被定义,那么就执行加密脚本 *//* 加密NSString类型的 */#define confusion_NSSTRING(string) @string/* 加密char *类型的 */#define confusion_CSTRING(string) string#endif@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    /* 使用confusion_NSSTRING宏包含需要加密的NSString字符串 */    NSString *str = confusion_NSSTRING("Hello World");    NSLog(@"%@",str);    /* 使用confusion_NSSTRING宏包含需要加密的char*字符串 */    char* cStr = confusion_CSTRING("Super Man");    NSLog(@"%s",cStr);    }
  • 步骤2 使用终端cd 到需要加密的工程目录下 执行 touch confusion.py 和 touch decrypt.py 命令,生产加密和解密脚本文件
  • 步骤3 把下面代码加入解密脚本confusion.py中
#!/usr/bin/env python# encoding=utf8# -*- coding: utf-8 -*-# author by heyujia# 脚本将会用于对指定目录下的.h .m源码中的字符串进行转换# 替换所有字符串常量为加密的char数组,形式((char[]){1, 2, 3, 0})import importlibimport osimport reimport sys# replace替换字符串为((char[]){1, 2, 3, 0})的形式,同时让每个字节与0xAA异或进行加密# 当然可以不使用0xAA 使用其他的十六进制也行 例如0XBB、0X22、0X11def replace(match):    string = match.group(2) + 'x00'    replaced_string = '((char []) {' + ', '.join(["%i" % ((ord(c) ^ 0xAA) if c != '0' else 0) for c in list(string)]) + '})'    return match.group(1) + replaced_string + match.group(3)# obfuscate方法是修改传入文件源代码中用confusion_NSSTRING标记的所有字符串# 使用replace函数对字符串进行异或转换def obfuscate(file):    with open(file, 'r') as f:        code = f.read()        f.close()        code = re.sub(r'(confusion_NSSTRING(|confusion_CSTRING()"(.*?)"())', replace, code)        code = re.sub(r'//#define ggh_confusion', '#define ggh_confusion', code)        with open(file, 'w') as f:            f.write(code)            f.close()# openSrcFile方法是读取源码路径下的所有.h和.m 文件# 对每个文件执行obfuscate函数def openSrcFile(path):    print("混淆的路径为 "+ path)    # this folder is custom    for parent,dirnames,filenames in os.walk(path):        #case 1:        #        for dirname in dirnames:        #            print((" parent folder is:" + parent).encode('utf-8'))        #            print((" dirname is:" + dirname).encode('utf-8'))        #case 2        for filename in filenames:            extendedName = os.path.splitext(os.path.join(parent,filename))            if (extendedName[1] == '.h' or extendedName[1] == '.m'):                print("处理源代码文件: "+ os.path.join(parent,filename))                obfuscate(os.path.join(parent,filename))#这里需要修改源码的路径为自己工程的文件夹名称srcPath = '../daimahunxiao'if __name__ == '__main__':    print("本脚本用于对源代码中被标记的字符串进行加密")        if len(srcPath) > 0:        openSrcFile(srcPath)    else:        print("请输入正确的源代码路径")        sys.exit()
  • 步骤4 把下面的解密代码放入decrypt.py解密脚本中
#!/usr/bin/env python# encoding=utf8# -*- coding: utf-8 -*-# author by heyujia# 解密脚本# 替换所有标记过的加密的char数组为字符串常量,""import importlibimport osimport reimport sys# 替换((char[]){1, 2, 3, 0})的形式为字符串,同时让每个数组值与0xAA异或进行解密def replace(match):    string = match.group(2)    decodeConfusion_string = ""    for numberStr in list(string.split(',')):        if int(numberStr) != 0:            decodeConfusion_string = decodeConfusion_string + "%c" % (int(numberStr) ^ 0xAA)    replaced_string = '"' + decodeConfusion_string + '"'    print("replaced_string = " + replaced_string)        return match.group(1) + replaced_string + match.group(3)# 修改源代码,加入字符串加密的函数def obfuscate(file):    with open(file, 'r') as f:        code = f.read()        f.close()        code = re.sub(r'(confusion_NSSTRING(|confusion_CSTRING()((char []) {(.*?)})())', replace, code)        code = re.sub(r'[/]*#define ggh_confusion', '//#define ggh_confusion', code)        with open(file, 'w') as f:            f.write(code)            f.close()#读取源码路径下的所有.h和.m 文件def openSrcFile(path):    print("解密路径: "+ path)    # this folder is custom    for parent,dirnames,filenames in os.walk(path):        #case 1:        #        for dirname in dirnames:        #            print((" parent folder is:" + parent).encode('utf-8'))        #            print((" dirname is:" + dirname).encode('utf-8'))        #case 2        for filename in filenames:            extendedName = os.path.splitext(os.path.join(parent,filename))            #读取所有.h和.m 的源文件            if (extendedName[1] == '.h' or extendedName[1] == '.m'):                print("已解密文件:"+ os.path.join(parent,filename))                obfuscate(os.path.join(parent,filename))#源码路径srcPath = '../daimahunxiao'if __name__ == '__main__':    print("字符串解混淆脚本,将被标记过的char数组转为字符串,并和0xAA异或。还原代码")    if len(srcPath) > 0:        openSrcFile(srcPath)    else:        print("请输入正确的源代码路径!")        sys.exit()
  • 步骤5 根据自己的需求修改下脚本里面的代码 和 文件路径。
  • 步骤6 把步骤1中的宏heyujia_confusion注释了,然后执行加密脚本,在终端中输入 python confusion.py ,
    (1.如果报错,请查看下自己Mac电脑中的python版本,如果是python3就输入 python3 confusion.py .
    (2.如果报 Non-ASCII character 'xe8' in file confusion.py on line 2 相关的错,请确定脚本的前面3行是
#!/usr/bin/env python# encoding=utf8# -*- coding: utf-8 -*-

执行完步骤6后的结果

c118873cc69ec4321e8049461a783e02.png

此时字符串已被加密,运行程序会发现一切正常

36aee6775d34ea9a2ec0993f58e4be4c.png
2d87960d78225192a693dc8a322a63f1.png

加密后汇编界面看不见我们的字符串内容了,但是我们用来解密的方法还是暴露在了汇编界面,所以我们后期还需要对方法名,变量名,类命等做混淆。

  • 步骤7 把步骤1中的宏heyujia_confusion取消注释,然后执行解密脚本,在终端中输入 python decrypt.py
88857c8ba71cb39516da63c4680f90fa.png
  • 解密后文本又变回了原样。

这里只是基本的异或转换加密,让代码中的字符串变成看不懂的char [],实际操作中远远不止这么简单 例如:

  • 首先:我们先用加密工具例如:AES.Base64等把需要转换的字符串先加密变成加密字符串
  • 然后:在用异或转换加密的脚本把加密字符串进行转换(包括解密用的钥匙串)
  • 在使用的时候:先异或解密字符串,然后根据解密钥匙串把字符串在转为可用的字符串

ps.还有一种保护字符串的方法,就是使用NSLocalizedString字符串本地化。

虽然跟着我的步骤你确实加密成功了,但是你却无法实际验证。所以要验证最终的混淆结果是否达到效果,你还需要学习如何破壳解密IPA如何动态静态逆向编程分析工程源码,大家可以先看看我 这篇文章 。先掌握逆向分析后再来做代码混淆,就能验证混淆结果是否有效

变量、方法名,类名混淆

对于混淆这一块,网上真的是千篇一律,基本都是copy的念大婶的内容,没有一点自己的创新和思考。网上的方法我也用过,但是有缺陷,只能混淆方法名或者说自己固定的内容去替换。第一不自动,对于大项目而言每个方法名自己添加,太麻烦。第二变量混淆有问题,因为只是单纯的字符串替换,用宏代替。当遇到使用_ 下划线访问变量时,就会出现错误。

对于变量、方法名,类名的混淆,其实跟字符串混淆差不多,都是加密混淆,然后解密混淆。不同的是,变量、方法名,类名的混淆目的是为了让别人反编译的时候不知道你的变量、方法,类是具体用来干什么的,不会像明文那样一目了然。增加逆向难度。混淆的内容不需要像字符串一样,最后程序运行时还要转成中文正常使用。由于本人对shell脚本语言也不是非常熟悉,想要按照自己的思路写一套完整的混淆脚本还不行。所以这部分也是在网上找的,算是目前最实用最完善的混淆

  • 首先 打开终端cd到需要混淆的工程目录下,输入
    touch obConfusion.sh (加密混淆脚本文件)
    touch obDecrypt.sh (解密混淆脚本文件)
    生成2个脚本文件
  • 然后在工程目录以外创建一个文件夹,用于保存加密时生成的加密文本内容,该内容会在解密时用到
  • 最后是在 obConfusion.sh 和 obDecrypt.sh 文件中加入脚本内容

下面是加密混淆脚本内容

#!/bin/sh###################################  (该脚本是在https://github.com/heqingliang/CodeObfus 上找到的)#  代码混淆脚本  heyujia 2018.03.15####################################识别含有多字节编码字符时遇到的解析冲突问题export LC_CTYPE=Cexport LANG=C#配置项:#项目路径,会混淆该路径下的文件ProjectPath="/Users/xieyujia/Desktop/ios/学习项目/daimahunxiao"#这个路径是混淆成功后,原文本和替换文本解密对应的文件存放路径(该路径不能在项目目录或其子目录),混淆成功后会在该路径下生成一个解密时需要的文件,根据该文件的文本内容把混淆后的内容更换为原文本内容,该文件名的组成由$(date +%Y%m%d)"_"$(date +%H%M)及日期_小时组成,每分钟会不一样。所以解密的时候需要每次更换文件路径SecretFile="/Users/xieyujia/Desktop/ios/学习项目/tihuan"$(date +%Y%m%d)"_"$(date +%H%M)#第一个参数为项目路径if [[ $1 ]]thenif [[ $1 != "_" ]]; thenProjectPath=$1fifi#第二个参数指定密钥文件路径及文件名if [[ $2 ]]thenif [[ $2 != "_" ]]; thenSecretFile=$2fifi###############################################################################查找文本中所有要求混淆的属性方法类,只会替换文本中ob_开头和_fus结尾的字符串(区分大小写,例如oB_就不会做混淆),如果注释内容有该类型的字符串,也会进行替换。对于使用 _下划线访问的变量属性,不会有影响,一样会替换成对应_的混淆内容。resultfiles=`grep 'ob_[A-Za-z0-9_]*_fus' -rl $ProjectPath`#查找结果为空则退出if [[ -z $resultfiles ]]thenecho "项目没有需要混淆的代码"exitelseecho "开始混淆代码..."echo  > $SecretFilefix=$(awk  'BEGIN{srand();k=0;}#随机数生成函数function random_int(min, max) {return int( rand()*(max-min+1) ) + min;}#随机字符串生成函数function random_string(len) {result="UCS"k;alpbetnum=split("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z", alpbet, ",");for (i=0; i 0) {tempstr=substr(x, RSTART, RLENGTH);#判断是否有之前已经找过的重复字符串for ( i = 0; i < k; i++ ){if (strarr[i] == tempstr){break;}}if(i $SecretFilerecordnum=1while [[ 1 == 1 ]]; dorecord=`echo $x|cut -d "|" -f$recordnum`if [[ -z $record ]]thenbreakfirecord1=`echo $record|cut -d ":" -f1`echo "原项:"$record1record2=`echo $record|cut -d ":" -f2`echo "加密项:"$record2#替换文件夹中所有文件的内容(支持正则)#单引号不能扩展sed -i '' "s/${record1}/${record2}/g" `grep $record1 -rl $ProjectPath`echo "第"$recordnum"项混淆代码处理完毕"let "recordnum = $recordnum + 1"done#查找需要混淆的文件名并替换filerecordnum=1while [[ 1 == 1 ]]; dofilerecord=`echo $x|cut -d "|" -f$filerecordnum`if [[ -z $filerecord ]]thenbreakfifilerecord1=`echo $filerecord|cut -d ":" -f1`#echo "原项:"$filerecord1filerecord2=`echo $filerecord|cut -d ":" -f2`#echo "加密项:"$filerecord2#改文件名find $ProjectPath -name $filerecord1"*"| awk 'BEGIN{frecord1="'"$filerecord1"'";frecord2="'"$filerecord2"'";finish=1}{filestr=$0;gsub(frecord1,frecord2,filestr);print "mv " $0 " " filestr";echo 第"finish"个混淆文件处理完毕";finish++;}'|bashlet "filerecordnum = $filerecordnum + 1"done

下面是解密混淆脚本的内容

#!/bin/sh########################################  代码还原脚本  RyoHo 2018.03.15########################################识别含有多字节编码字符时遇到的解析冲突问题export LC_CTYPE=Cexport LANG=C#配置项:#已经混淆的项目路径ProjectPath="/Users/xieyujia/Desktop/ios/学习项目/daimahunxiao"#这个是文件路径而不是目录,是混淆的时候生成的文本文件路径,每次不一样。所以每次加密后,解密时需要更换路径SecretFile="/Users/xieyujia/Desktop/ios/学习项目/tihuan20180315_1456"#第一个参数为项目路径if [[ $1 ]]thenif [[ $1 != "_" ]]; thenProjectPath=$1fifi#第二个参数指定密钥文件路径及文件名if [[ $2 ]]thenif [[ $2 != "_" ]]; thenSecretFile=$2fifi###############################################################################内容还原x=`cat $SecretFile`recordnum=1while [[ 1 == 1 ]]; dorecord=`echo $x|cut -d "|" -f$recordnum`if [[ -z $record ]]thenbreakfirecord1=`echo $record|cut -d ":" -f1`echo "原项:"$record1record2=`echo $record|cut -d ":" -f2`echo "加密项:"$record2#若项目中加密项与密钥文件的加密项不符合则退出程序searchresult=`grep $record2 -rl $ProjectPath`if [[ -z $searchresult ]]; thenecho "指定的密钥文件不能还原"exitfi#替换文件夹中所有文件的内容(支持正则)#单引号不能扩展sed -i '' "s/${record2}/${record1}/g" $searchresultecho "第"$recordnum"项混淆代码还原完毕"let "recordnum = $recordnum + 1"done#文件还原filerecordnum=1while [[ 1 == 1 ]]; dofilerecord=`echo $x|cut -d "|" -f$filerecordnum`if [[ -z $filerecord ]]thenbreakfifilerecord1=`echo $filerecord|cut -d ":" -f1`#echo "原项:"$filerecord1filerecord2=`echo $filerecord|cut -d ":" -f2`#echo "加密项:"$filerecord2#改文件名find $ProjectPath -name $filerecord2"*"| awk 'BEGIN{frecord1="'"$filerecord1"'";frecord2="'"$filerecord2"'";finish=1;}{filestr=$0;gsub(frecord2,frecord1,filestr);print "mv " $0 " "filestr ";echo 第"finish"个混淆文件还原完毕"finish++;}'|bashlet "filerecordnum = $filerecordnum + 1"done

应大家需要把脚本源码:https://github.com/xkftkffz/DMHXDemo 地址 放出来

建议大家看看脚本内容,有利于学习理解。该脚本是有针对性的混淆内容,可以自己修改脚本中的正则表达式来确定混淆的内容。脚本中只会替换文本中ob_开头和_fus结尾的字符串(区分大小写,例如oB_就不会做混淆),如果注释内容有该类型的字符串,也会进行替换。对于使用 _下划线访问的变量属性,不会有影响,一样会替换成对应_的混淆内容。

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

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

相关文章

DARPA计划在2021年开展多种新型武器概念研究

来源&#xff1a;中国指挥与控制学会“远射”项目DARPA计划于2021年投资2200万美元启动“远射”项目&#xff0c;演示一种空射武器系统。该系统由速度较慢的远程飞行器搭载至战区&#xff0c;在战区上空发射多枚空空导弹来实施作战。该武器可由现有战斗机外部挂载&#xff0c;或…

python算法实现源码_Python实现七个基本算法

1.顺序查找当数据存储在诸如列表的集合中时&#xff0c;我们说这些数据具有线性或顺序关系。 每个数据元素都存储在相对于其他数据元素的位置。 由于这些索引值是有序的&#xff0c;我们可以按顺序访问它们。 这个过程产实现的搜索即为顺序查找。顺序查找原理剖析&#xff1a;从…

python词云设计实例_python词云库wordcloud的使用方法与实例详解

wordcloud是优秀的词云展示第三方库一、基本使用 import jieba import wordcloud txt open("1.txt", "r", encodingutf-8).read() words jieba.lcut(txt) txt_1 " ".join(words) # print(txt1) w wordcloud.WordCloud(font_path"msyh.t…

细胞因子风暴与新冠肺炎

来源&#xff1a;陈辉科学网博客链接地址&#xff1a;http://blog.sciencenet.cn/blog-3426569-1219679.html 2020年2月15日下午&#xff0c;在国务院联发联控机制新闻发布会上&#xff0c;周琪院士介绍说“炎症因子风暴”[作者注释&#xff1a;即是细胞因子风暴&#xff08;Cy…

mysql 启动 修改密码_基础的启动/停止/重启/密码修改MySQL

如何启动/停止/重启MySQL一、启动方式1、使用 service 启动&#xff1a;service mysqld start2、使用 mysqld脚本启动&#xff1a;/etc/inint.d/mysqld start3、使用 safe_mysqld启动&#xff1a;safe_mysqld&二、停止1、使用 service 启动&#xff1a;service mysqldstop2…

预编译对象解决SQL注入问题

转载于:https://www.cnblogs.com/suanshun/p/6739454.html

eclipse中添加jar包后运行时提示noclassdeffounderror_一看你就懂,超详细 java 中的 ClassLoader 详解,耐心看~...

备注&#xff1a;本文篇幅比较长&#xff0c;但内容简单&#xff0c;大家不要恐慌&#xff0c;安静地耐心翻阅就是Class文件的认识我们都知道在Java中程序是运行在虚拟机中&#xff0c;我们平常用文本编辑器或者是IDE编写的程序都是.java格式的文件&#xff0c;这是最基础的源码…

寻找人机之间的中间地带-评述3本人机协作的书

来源&#xff1a; 混沌巡洋舰1 AI 错觉知其然&#xff0c;更要知其所以然&#xff0c;了解数据挖掘的算法的基础原理&#xff0c;可以在这个人工智能和大数据可能比工业革命更能改变人的一生的历史时期中&#xff0c;更有智慧的应用人工智能。AI错觉这本书18年在美国出版&#…

TypeError: HashUpdate fail

关于crypto的md5加密报错&#xff1a; 代码&#xff1a; var crypto require(crypto); var md5 crypto.createHash(md5); //crypto模块功能是加密并生成各种散列 var oldpass md5.update(oldpass).digest(hex); var newpass md5.update(newpass).digest(hex);如果md5.updat…

mysql 与gemfire的同步_(转)分布式缓存GemFire架构介绍

1什么是GemFireGemFire是一个位于应用集群和后端数据源之间的高性能、分布式的操作数据(operational data)管理基础架构。它提供了低延迟、高吞吐量的数据共享和事件分发。GemFire充分利用网络中的内存和磁盘资源&#xff0c;形成一个实时的数据网格(data fabric or grid)。Gem…

混合云关键技术能力和发展趋势

来源&#xff1a;IDC圈为满足成本、按需、隐私、合规、避免供应商锁定等目的&#xff0c;企业常常会采用多个公有云或私有云&#xff0c;这会造成基础设施资源池多样化&#xff0c;还要面临同时管理物理机、虚拟化等异构资源环境。多云管理由于面临同时管理物理机、虚拟化等异构…

文字竖着写怎么设置_微信置顶文字怎么设置 微信置顶文字的方法介绍|微信|置顶软硬件资讯川北在线...

阅读本文前&#xff0c;请您先点击上面的“蓝色字体”&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到文章了。每天都会有分享&#xff0c;都是免费订阅&#xff0c;请您放心关注。注&#xff1a;本文转载自网络&#xff0c;不代表本平台立场&#xff0c;仅供…

DOM查找元素的方法总结

按HTML查找&#xff1a;优点&#xff1a;范围可大可小&#xff0c;可设置条件&#xff1b;包括五种方式&#xff1a;1.按id查找&#xff1b;2.按标签名查找&#xff1a;var elems parent.getElementsByTagName();3.按name属性查找&#xff1a;要回传给服务器的元素需要name属性…

2019 NLP大全:论文、博客、教程、工程进展全梳理(长文预警)

来源&#xff1a;机器学习研究会订阅号在整个2019年&#xff0c;NLP领域都沉淀了哪些东西&#xff1f;有没有什么是你错过的&#xff1f;如果觉得自己梳理太费时&#xff0c;不妨看一下本文作者整理的结果。2019 年对自然语言处理&#xff08;NLP&#xff09;来说是令人印象深刻…

collection集合 地址_java集合系列(5)LinkedList

这篇文章开始介绍LinkList。他和ArrayList有一些相似&#xff0c;在上一篇文章讲解 ArrayList时&#xff0c;我们知道ArrayList是以数组实现&#xff0c;它的优势是查询性能高&#xff0c;劣势是按顺序增删性能差。如果在不确定元素数量的情况时&#xff0c;不建议使用ArrayLis…

meanshift算法 java_Meanshift,聚类算法

记得刚读研究生的时候&#xff0c;学习的第一个算法就是meanshift算法&#xff0c;所以一直记忆犹新&#xff0c;今天和大家分享一下Meanshift算法&#xff0c;如有错误&#xff0c;请在线交流。Mean Shift算法,一般是指一个迭代的步骤,即先算出当前点的偏移均值,移动该点到其偏…

python 数据分析 电信_实例 | 教你用Python写一个电信客户流失预测模型

原标题&#xff1a;实例 | 教你用Python写一个电信客户流失预测模型CDA数据分析师 出品 作者&#xff1a;真达、Mika 数据&#xff1a;真达 【导读】 今天教大家如何用Python写一个电信用户流失预测模型。公众号后台&#xff0c;回复关键字“电信”获取完整数据。 之前我们用Py…

人机融合智能与深度态势感知

来源&#xff1a;人机与认知实验室【“常无欲以观其妙&#xff0c;常有欲以观其徼。”&#xff0c;意思是身处物外可以以旁观者的身份来看待事物&#xff0c;身处事内则要考虑各种极限。】0 引言伴随着深度学习[1]、强化学习[2]等新一代人工智能技术的发展&#xff0c;智能化已…

java大数模板_java大数模板

这几天做了几道用大数的题&#xff0c;发现java来做大数运算十分方便。对acmer来说是十分实用的1.valueOf(parament); 将参数转换为制定的类型比如 int a3;BigInteger bBigInteger.valueOf(a);则b3;String s”12345”;BigInteger cBigInteger.valueOf(s);则c12345&#xff1b;2…

20162317 2016-2017-2 《程序设计与数据结构》第8周学习总结

20162317 2016-2017-2 《程序设计与数据结构》第8周学习总结 教材学习内容总结 1.异常的定义&#xff08;中断正常指令的事件&#xff09; 2.异常的特点&#xff08;异常是对象&#xff09; 3.异常的分类&#xff08;CheckedExcception 和 UncheckedException&#xff09; 4.异…