对梆梆APP加固产品方案进行简要分析
目录:
一、APP加固背景
二、APP加固前世今生
三、整体框架
四、详细流程分析
五、总结
一、APP加固背景
1.1、概述
Android系统是基于Linux开发己具有其开放性、*性的一种操作系统,现主要应用于移动设备,如手机、平板电脑和车载系统等。从2007年Google推出第一代Android操作系统至今已有10多年的时间,移动行业的市场份额与规模也在急速增长,现在几乎每人都在用或曾用过接触过Android智能手机。
1.2、安全问题
移动APP越来越普及,大多业务己放到APP中完 成,带来的安全隐患也越来越突出,漏洞、APP破解、恶意代码植入、广告植入、病毒木马、支付篡改、数据爬取等安全问题。
在发版前可通过对APP进行安全检测,加固APP可以提高安全性,解决大部分风险。
二、APP加固前世今生
2.1、APP加固发展与现状
App加固技术,前后经历了四代技术变更,保护级别在每一代都有所提升,破解成本也越来超高,发展流程大致如图2-1所示:
图2-1
第一代加固技术(动态加载):
第一代Android加固技术用于保护应用的逻辑不被逆向与分析,最早普遍在恶意软件中使用,其主要基于虚拟机提供的动态加载技术。
缺陷:只能对抗静态分析,无法对抗攻击者通过动态调试或自定义虚拟机进行脱壳。
第二代加固技术(内存加载):
第二代加固技术在APK修改方面已经完善,能做到对开发的零干扰。开发过程中不需要对应用做特殊处理,只需要在最终发布前进行保护即可。而为了实现这个零干扰的流程,Loader需要处理好Android的组件的生命周期。hook读写等方法,读写文件时进行加解密。
缺陷:只能对抗静态分析,无法对抗攻击者通过动态调试、内存dump或自定义虚拟机进行脱壳。
第三代加固技术(指令抽取):
第三代加固技术对Dex中代码的方法名和方法体进行分离,并对分离的方法体进行加密,通过Hook虚拟机方法,在程序运行的同时对方法进行解密运行。这种保护技术有效的防止了破解者通过内存dump的方式获取明文dex,将保护级别降到了函数级别。
缺陷:无法对抗攻击者通过自定义Android虚拟机进行脱壳。
第四代加固技术(java2C/VMP):
第四代加固技术对DEX中方法提取并转化成native方法后在底层进行注册,在调用native方法的同时在底层使用自定义解释器解释虚拟机指令。
java2c是将DEX文件内的函数被标记为native,内容被抽离并转换成一个符合JNI要求的动态库。动态库内通过JNI方法和Android系统进行交互。
缺陷:不论VMP还是java2c,都必须通过虚拟机提供的JNI接口与虚拟机进行交互,攻击者可以直接hook系统JNI接口、记录和分析执行流程,进而推断出完整DEX程序。
2.1、产品介绍
梆梆加固产品主要分为免费版与定制版,应用场景如下:
防逆向(Anti-RE) :
抽取classes.dex中的所有代码,剥离敏感函数功能,混淆关键逻辑代码,整体文件深度加密加壳,防止通过apktool,dex2jar,JEB等静态工具来查看应用的Java层代码,防止通过IDA,readelf等工具对so里面的逻辑进行分析,保护native代码。
防篡改(Anti-tamper)
每个代码文件、资源文件、配置文件都会分配唯一识别指纹,替换任何一个文件,将会导致应用无法运行,存档替换、病毒广告植入、内购破解、功能屏蔽等恶意行为将无法实施。
防调试(Anti-debug)
多重加密技术防止代码注入,彻底屏蔽游戏外挂、应用辅助工具,避免钓鱼攻击、交易劫持、数据修改等调试行为。
防窃取(Storage Encryption)
支持存储数据加密,提供输入键盘保护、通讯协议加密、内存数据变换、异常进程动态跟踪等安防技术,有效防止针对应用动、静态数据的捕获、劫持和篡改。 免费版与定制版本区别如图2-2所示:
图2-2
免费版本相对于定制化加固在安全能力方面要弱很多,我们分析的目标是定制版本的加固。
三、整体框架
梆梆定制版加固保护代码的方式主要分为两种,一是指令抽取,二是指令虚拟化,指令还原与虚拟化基本的流程与逻辑如图3-1所示:
图3-1
四、详细流程分析
4.1 加固后APP基本情况介绍
通过JEB反编译DUMP出来的DEX,方法指令抽取与指令虚拟化后如图4-1与4-2所示,方法指令抽取后的结果如图4-1所示:
图4-1
方法指令虚拟化后大部分函数是调用JniLib.cV解析执行的,最后一个参数是一个函数code索引,用来查找被虚拟化后的指令,其它是方法参数,如图4-2所示:
图4-2
4.2 So壳简单分析
壳的SO文件本身做了加壳保护,壳入口为.init_proc,如图4-3所示:
图4-3
解壳流程如大致为获取加密的代码基址->解密->修改属性,解密代码如下:
#define CODE_DATA_SIZE 0X00053DB3 #define CODE_DATA_OFFSET 0XE500 int DecCode(int copydata, unsigned int datasize, int codebufer, int* a4) { index_2 = 0; v5 = 1; index = 0; v7 = 0; while (1) { while (1) { v8 = (v7 & 0x7F) == 0; if ((v7 & 0x7F) != 0) v7 *= 2; else v7 = *(unsigned __int8*)(copydata + index); if (v8) { v7 = 2 * v7 + 1; ++index; } if ((v7 & 0x100) == 0) break; codebyte = *(unsigned char*)(copydata + index++); *(unsigned char*)(codebufer + index_2++) = codebyte; } for (i = 1; ; i = v20 + ((unsigned int)(v7 << 23) >> 31)) { v11 = (v7 & 0x7F) == 0; if ((v7 & 0x7F) != 0) v12 = 2 * v7; else v12 = *(unsigned __int8*)(copydata + index); if (v11) { v12 = 2 * v12 + 1; ++index; } v13 = (v12 & 0x7F) == 0; v14 = v12 << 23; if ((v12 & 0x7F) != 0) v15 = 2 * v12; else v15 = *(unsigned __int8*)(copydata + index); if (v13) v15 = 2 * v15 + 1; v16 = 2 * i; if (v13) ++index; v17 = v16 + (v14 >> 31); if ((v15 & 0x100) != 0) break; v18 = (v15 & 0x7F) == 0; if ((v15 & 0x7F) == 0) v15 = *(unsigned __int8*)(copydata + index); v19 = v17 + 0x7FFFFFFF; v7 = 2 * v15; if (v18) ++v7; v20 = 2 * v19; if (v18) ++index; } index_1 = index; if (v17 != 2) break; v22 = (v15 & 0x7F) == 0; if ((v15 & 0x7F) != 0) v15 *= 2; else v15 = *(unsigned __int8*)(copydata + index); if (v22) v15 = 2 * v15 + 1; if (v22) ++index; v23 = (v15 >> 8) & 1; LABEL_41: v25 = (v15 & 0x7F) == 0; if ((v15 & 0x7F) != 0) v7 = 2 * v15; else v7 = *(unsigned __int8*)(copydata + index); if (v25) v7 = 2 * v7 + 1; v26 = 2 * v23; if (v25) ++index; v27 = v26 + ((unsigned int)(v7 << 23) >> 31); if (!v27) { v28 = 1; do { v29 = (v7 & 0x7F) == 0; if ((v7 & 0x7F) != 0) v30 = 2 * v7; else v30 = *(unsigned __int8*)(copydata + index); if (v29) { v30 = 2 * v30 + 1; ++index; } v31 = (v30 & 0x7F) == 0; v32 = v30 << 23; if ((v30 & 0x7F) != 0) v7 = 2 * v30; else v7 = *(unsigned __int8*)(copydata + index); if (v31) v7 = 2 * v7 + 1; v33 = 2 * v28; if (v31) ++index; v28 = v33 + (v32 >> 31); } while ((v7 & 0x100) == 0); v27 = v28 + 2; } if (v5 > 0x500) v34 = v27 + 1; else v34 = v27; v35 = (unsigned char*)(codebufer + index_2 - v5); *(unsigned char*)(codebufer + index_2) = *v35; v36 = index_2 + 1; v37 = &v35[v34]; v38 = codebufer + index_2; do { v39 = *++v35; *(unsigned char*)++v38 = v39; } while (v35 != v37); index_2 = v36 + v34; } v24 = *(unsigned __int8*)(copydata + index++) + ((v17 + 16777213) << 8); if (v24 != -1) { v23 = !(*(unsigned char*)(copydata + index_1) & 1); v5 = (v24 >> 1) + 1; goto LABEL_41; } *a4 = index_2; if (index == datasize) return 0; if (index >= datasize) return -201; return -205; } int __fastcall sub_D1F2EA88(int result, int a2) { int v2; // r4 unsigned int v3; // r12 int v4; // r6 int v5; // r7 int v6; // r5 int v7; // r2 unsigned int v8; // r5 int v9; // r3 int v10; // r6 unsigned int v11; // r1 v2 = *(int*)(result + a2 + 8); v3 = *(int*)(result + a2 + 12); v4 = *(int*)(result + a2 + 16); v5 = *(int*)(result + a2 + 20); v6 = *(int*)(result + a2 + 24); if (*(int*)(result + a2) == 2146926590) { result += *(int*)(result + a2 + 4); v7 = 0; v8 = v3 + 4 * v6; v9 = 0; v10 = v5 + v4; while (v9 != v2) { v11 = *(int*)(result + 8 * v9); if (v11 >= v3 && v11 < v8) * (int*)(result + 8 * v9) = v10 + 4 * v7++; ++v9; } } return result; }
4.3 DEX 指令抽取原理分析
JNI_OnLoad 分析
壳解密完成后执行到JNI_OnLoad方法,JNI_OnLoad主要完成几个重要步骤。
1、注册JNI方法,方法如下:
i()V attach(Landroid/app/Application;Landroid/content/Context;)V b(Landroid/content/Context;Landroid/app/Application;)V c()V d(Ljava/lang/String;)Ljava/lang/String; e(Ljava/lang/Object;Ljava/util/List;Ljava/lang/String;)[Ljava/lang/Object; f()[Ljava/lang/String; g()[Ljava/lang/String; h()[Ljava/lang/String; n()[Ljava/lang/String; j()[Ljava/lang/String; k()Ljava/lang/String; l()Ljava/lang/String; m()Ljava/lang/String;
2、hook libc.so方法,hook如下方法:
__open
__openat
write
read
munmap
msync
__mmap2
pread64
ftruncate64
close
3、读取classes0.jar、classes.dgc并解密,代码逻辑如下:
//读取资源文件 seg131:CEE8E1B0 01 1C MOVS R1, R0 seg131:CEE8E1B2 06 98 LDR R0, [SP,#0x18] seg131:CEE8E1B4 D1 F7 A4 EA BLX AAssetManager_fromJava_0 seg131:CEE8E1B8 31 1C MOVS R1, R6 seg131:CEE8E1BA 03 22 MOVS R2, #3 seg131:CEE8E1BC D1 F7 A6 EA BLX AAssetManager_open_0 seg131:CEE8E1C0 17 90 STR R0, [SP,#0x5C] seg131:CEE8E1C2 D1 F7 B0 EA BLX AAsset_getBuffer_0 seg131:CEE8E1C6 1D 90 STR R0, [SP,#0x74] seg131:CEE8E1C8 ; START OF FUNCTION CHUNK FOR map_bufer seg131:CEE8E1C8 seg131:CEE8E1C8 loc_CEE8E1C8 ; CODE XREF: map_bufer+62↑j seg131:CEE8E1C8 17 98 LDR R0, [SP,#0x5C] ; asset seg131:CEE8E1CA D1 F7 A6 EA BLX AAsset_getLength_0 seg131:CEE8E1CE 00 23 MOVS R3, #0 seg131:CEE8E1D0 33 93 STR R3, [SP,#0xCC] seg131:CEE8E1D2 33 9A LDR R2, [SP,#0xCC] seg131:CEE8E1D4 A4 4A LDR R2, =0xFFFFFC84 //解密代码 seg131:CEE72568 EXPORT Dec_classes_dgc_p1053869DF5E0CBA2E958A4809845A982 seg131:CEE72568 Dec_classes_dgc_p1053869DF5E0CBA2E958A4809845A982 seg131:CEE72568 var_248= -0x248 seg131:CEE72568 var_244= -0x244 seg131:CEE72568 var_240= -0x240 seg131:CEE72568 var_238= -0x238 seg131:CEE72568 var_11C= -0x11C seg131:CEE72568 var_1C= -0x1C seg131:CEE72568 arg_48= 0x48 seg131:CEE72568 arg_314= 0x314 seg131:CEE72568 F0 B5 PUSH {R4-R7,LR} seg131:CEE7256A 87 4C LDR R4, loc_CEE72788 seg131:CEE7256C 87 4A LDR R2, loc_CEE7278C seg131:CEE7256E 88 4B LDR R3, loc_CEE72790 seg131:CEE72570 A5 44 ADD SP, R4 seg131:CEE72572 01 90 STR R0, [SP,#0x248+var_244] seg131:CEE72574 80 20 MOVS R0, #0x80 seg131:CEE72576 7A 44 ADD R2, PC seg131:CEE72578 D6 58 LDR R6, [R2,R3] seg131:CEE7257A 00 91 STR R1, [SP,#0x248+var_248] seg131:CEE7257C seg131:CEE7257C loc_CEE7257C seg131:CEE7257C 80 02 LSLS R0, R0, #0xA seg131:CEE7257E 33 68 LDR R3, [R6] seg131:CEE72580 04 96 STR R6, [SP,#0x248+var_238] seg131:CEE72582 8B 93 STR R3, [SP,#0x248+var_1C] seg131:CEE72584 81 42 CMP R1, R0 seg131:CEE72586 00 DD BLE loc_CEE7258A seg131:CEE72588 00 90 STR R0, [SP,#0x248+var_248] seg131:CEE7258A seg131:CEE7258A loc_CEE7258A seg131:CEE7258A 82 4B LDR R3, loc_CEE72794 seg131:CEE7258C 7B 44 ADD R3, PC seg131:CEE7258E 1B 68 LDR R3, [R3] seg131:CEE72590 00 2B CMP R3, #0 seg131:CEE72592 40 D1 BNE loc_CEE72616 seg131:CEE72594 80 49 LDR R1, loc_CEE72798 seg131:CEE72596 52 58 LDR R2, [R2,R1] seg131:CEE72598 12 68 LDR R2, [R2] seg131:CEE7259A 02 92 STR R2, [SP,#0x248+var_240] seg131:CEE7259C 80 22 52 00 MOVS R2, #0x100 seg131:CEE725A0 seg131:CEE725A0 loc_CEE725A0 seg131:CEE725A0 4B A9 ADD R1, SP, #0x248+var_11C seg131:CEE725A2 5B 54 STRB R3, [R3,R1] seg131:CEE725A4 seg131:CEE725A4 loc_CEE725A4 seg131:CEE725A4 01 33 ADDS R3, #1 seg131:CEE725A6 93 42 CMP R3, R2 seg131:CEE725A8 FA D1 BNE loc_CEE725A0 seg131:CEE725AA 00 23 MOVS R3, #0 seg131:CEE725AC 0F 27 MOVS R7, #0xF seg131:CEE725AE 1D 1C MOVS R5, R3 seg131:CEE725B0 18 1C MOVS R0, R3 seg131:CEE725B2 9C 46 MOV R12, R3 seg131:CEE725B4 seg131:CEE725B4 loc_CEE725B4 seg131:CEE725B4 02 9A LDR R2, [SP,#(dword_CEE727D4 - 0xCEE727CC)] seg131:CEE725B6 46 5C LDRB R6, [R0,R1] seg131:CEE725B8 seg131:CEE725B8 loc_CEE725B8 seg131:CEE725B8 64 46 MOV R4, R12 seg131:CEE725BA D2 5C LDRB R2, [R2,R3] seg131:CEE725BC 01 33 ADDS R3, #1 seg131:CEE725BE 92 19 ADDS R2, R2, R6 seg131:CEE725C0 55 19 ADDS R5, R2, R5 seg131:CEE725C2 FF 22 MOVS R2, #0xFF seg131:CEE725C4 15 40 ANDS R5, R2 seg131:CEE725C6 DA 0F LSRS R2, R3, #0x1F seg131:CEE725C8 seg131:CEE725C8 loc_CEE725C8 seg131:CEE725C8 9F 42 CMP R7, R3 seg131:CEE725CA seg131:CEE725CA loc_CEE725CA seg131:CEE725CA 62 41 ADCS R2, R4 seg131:CEE725CC 52 42 NEGS R2, R2 seg131:CEE725CE 13 40 ANDS R3, R2 seg131:CEE725D0 seg131:CEE725D0 loc_CEE725D0 seg131:CEE725D0 4A 5D LDRB R2, [R1,R5] seg131:CEE725D2 0A 54 STRB R2, [R1,R0] seg131:CEE725D4 80 22 MOVS R2, #0x80 seg131:CEE725D6 01 30 ADDS R0, #1 seg131:CEE725D8 4E 55 STRB R6, [R1,R5] seg131:CEE725DA 52 00 LSLS R2, R2, #1 seg131:CEE725DC 90 42 CMP R0, R2 seg131:CEE725DE E9 D1 BNE loc_CEE725B4 seg131:CEE725DE seg131:CEE725DE seg131:CEE725E0 seg131:CEE725E0 seg131:CEE725E0 loc_CEE725E0 seg131:CEE725E0 00 22 MOVS R2, #0 seg131:CEE725E2 FF 27 MOVS R7, #0xFF seg131:CEE725E4 10 1C MOVS R0, R2 seg131:CEE725E6 01 99 LDR R1, [SP,#4] seg131:CEE725E8 00 9B LDR R3, [SP] seg131:CEE725EA CC 18 ADDS R4, R1, R3 seg131:CEE725EC ; START OF FUNCTION CHUNK FOR DecString_5 seg131:CEE725EC seg131:CEE725EC loc_CEE725EC seg131:CEE725EC seg131:CEE725EC A1 42 CMP R1, R4 seg131:CEE725EE 00 D1 BNE loc_CEE725F2 seg131:CEE725F0 BE E0 B loc_CEE72770 seg131:CEE725F2 seg131:CEE725F2 loc_CEE725F2 seg131:CEE725F2 01 30 ADDS R0, #1 seg131:CEE725F4 seg131:CEE725F4 loc_CEE725F4 seg131:CEE725F4 4B AE ADD R6, SP, #0x248+var_11C seg131:CEE725F6 38 40 ANDS R0, R7 seg131:CEE725F8 33 5C LDRB R3, [R6,R0] seg131:CEE725FA seg131:CEE725FA loc_CEE725FA seg131:CEE725FA D2 18 ADDS R2, R2, R3 seg131:CEE725FC 3A 40 ANDS R2, R7 seg131:CEE725FE B5 5C LDRB R5, [R6,R2] seg131:CEE72600 35 54 STRB R5, [R6,R0] seg131:CEE72602 B3 54 STRB R3, [R6,R2] seg131:CEE72604 35 5C LDRB R5, [R6,R0] seg131:CEE72606 ED 18 ADDS R5, R5, R3 seg131:CEE72608 3D 40 ANDS R5, R7 seg131:CEE7260A 0B 78 LDRB R3, [R1] seg131:CEE7260C 75 5D LDRB R5, [R6,R5] seg131:CEE7260E 6B 40 EORS R3, R5 seg131:CEE72610 0B 70 STRB R3, [R1] seg131:CEE72612 01 31 ADDS R1, #1 seg131:CEE72614 EA E7 B loc_CEE725EC seg131:CEE72616 seg131:CEE72616 loc_CEE72616 seg131:CEE72616 01 2B CMP R3, #1 seg131:CEE72618 00 D0 BEQ loc_CEE7261C seg131:CEE7261A seg131:CEE7261A loc_CEE7261A seg131:CEE7261A A9 E0 B loc_CEE72770 seg131:CEE7261C seg131:CEE7261C loc_CEE7261C seg131:CEE7261C 5E 4B LDR R3, loc_CEE72798 seg131:CEE7261E 06 A8 ADD R0, SP, #0x248+var_230 seg131:CEE72620 D3 58 LDR R3, [R2,R3] seg131:CEE72620 ; END OF FUNCTION CHUNK FOR DecString_5 seg131:CEE72622 19 68 LDR R1, [R3] seg131:CEE72624 FF F7 48 FC BL _Z33p70A9D4C5060D53A50764B3505C16E6F2P33p4ABCBA1E0CA9993D681F7E561B3486DCPh seg131:CEE72628 00 98 LDR R0, [SP] seg131:CEE7262A EC F7 98 EF BLX malloc_0 seg131:CEE7262E 01 99 LDR R1, [SP,#4] seg131:CEE72630 00 9A LDR R2, [SP] seg131:CEE72632 06 1C MOVS R6, R0 seg131:CEE72634 EC F7 80 EF BLX memcpy_0_ seg131:CEE72638 01 9D LDR R5, [SP,#4] seg131:CEE7263A loc_CEE7263A seg131:CEE7263A 00 9B LDR R3, [SP,#0x130+var_130] seg131:CEE7263C seg131:CEE7263C loc_CEE7263C seg131:CEE7263C 01 9A LDR R2, [SP,#0x130+var_12C] seg131:CEE7263E 5B 1B SUBS R3, R3, R5 seg131:CEE72640 D3 18 ADDS R3, R2, R3 seg131:CEE72642 00 2B CMP R3, #(unk_13F0E000 - 0x13F0E000) seg131:CEE72644 seg131:CEE72644 loc_CEE72644 seg131:CEE72644 00 DC BGT loc_CEE72648 seg131:CEE72646 93 E0 B loc_CEE72770 seg131:CEE72648 loc_CEE72648 seg131:CEE72648 27 AF ADD R7, SP, #0x130+var_94 seg131:CEE7264A 00 21上一篇: 汇编指令探析:JCC指令的用法详解
推荐阅读
对梆梆APP加固产品方案进行简要分析
分析梆梆APP加固产品方案的基本特点
包婷婷 (201550484)作业一 统计软件简介与数据操作-SPSS(Statistical Product and Service Solutions),"统计产品与服务解决方案"软件。最初软件全称为"(SolutionsStatistical Package for the Social Sciences),但是随着SPSS产品服务领域的扩大和服务深度的增加,SPSS公司已于2000年正式将英文全称更改为"统计产品与服务解决方案",标志着SPSS的战略方向正在做出重大调整。为IBM公司推出的一系列用于统计学分析运算、数据挖掘、预测分析和决策支持任务的软件产品及相关服务的总称SPSS,有Windows和Mac OS X等版本。 1984年SPSS总部首先推出了世界上第一个统计分析软件微机版本SPSS/PC+,开创了SPSS微机系列产品的开发方向,极大地扩充了它的应用范围,并使其能很快地应用于自然科学、技术科学、社会科学的各个领域。世界上许多有影响的报刊杂志纷纷就SPSS的自动统计绘图、数据的深入分析、使用方便、功能齐全等方面给予了高度的评价。 R统计软件介绍 R是一套完整的数据处理、计算和制图软件系统。其功能包括:数据存储和处理系统;数组运算工具(其向量、矩阵运算方面功能尤其强大);完整连贯的统计分析工具;优秀的统计制图功能;简便而强大的编程语言:可操纵数据的输入和输出,可实现分支、循环,用户可自定义功能。 与其说R是一种统计软件,还不如说R是一种数学计算的环境,因为R并不是仅仅提供若干统计程序、使用者只需指定数据库和若干参数便可进行一个统计分析。R的思想是:它可以提供一些集成的统计工具,但更大量的是它提供各种数学计算、统计计算的函数,从而使使用者能灵活机动的进行数据分析,甚至创造出符合需要的新的统计计算方法。 该语言的语法表面上类似 C,但在语义上是函数设计语言(functional programming language)的变种并且和Lisp 以及 APL有很强的兼容性。特别的是,它允许在"语言上计算"(computing on the language)。这使得它可以把表达式作为函数的输入参数,而这种做法对统计模拟和绘图非常有用。 R是一个免费的*软件,它有UNIX、LINUX、MacOS和WINDOWS版本,都是可以免费下载和使用的。在R主页那儿可以下载到R的安装程序、各种外挂程序和文档。在R的安装程序中只包含了8个基础模块,其他外在模块可以通过CRAN获得。 二、R语言 R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个*、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。 R作为一种统计分析软件,是集统计分析与图形显示于一体的。它可以运行于UNIX,Windows和Macintosh的操作系统上,而且嵌入了一个非常方便实用的帮助系统,相比于其他统计分析软件,R还有以下特点: 1.R是*软件。这意味着它是完全免费,开放源代码的。可以在它的网站及其镜像中下载任何有关的安装程序、源代码、程序包及其源代码、文档资料。标准的安装文件身自身就带有许多模块和内嵌统计函数,安装好后可以直接实现许多常用的统计功能。[2] 2.R是一种可编程的语言。作为一个开放的统计编程环境,语法通俗易懂,很容易学会和掌握语言的语法。而且学会之后,我们可以编制自己的函数来扩展现有的语言。这也就是为什么它的更新速度比一般统计软件,如,SPSS,SAS等快得多。大多数最新的统计方法和技术都可以在R中直接得到。[2] 3. 所有R的函数和数据集是保存在程序包里面的。只有当一个包被载入时,它的内容才可以被访问。一些常用、基本的程序包已经被收入了标准安装文件中,随着新的统计分析方法的出现,标准安装文件中所包含的程序包也随着版本的更新而不断变化。在另外版安装文件中,已经包含的程序包有:base一R的基础模块、mle一极大似然估计模块、ts一时间序列分析模块、mva一多元统计分析模块、survival一生存分析模块等等.[2] 4.R具有很强的互动性。除了图形输出是在另外的窗口处,它的输入输出窗口都是在同一个窗口进行的,输入语法中如果出现错误会马上在窗口口中得到提示,对以前输入过的命令有记忆功能,可以随时再现、编辑修改以满足用户的需要。输出的图形可以直接保存为JPG,BMP,PNG等图片格式,还可以直接保存为PDF文件。另外,和其他编程语言和数据库之间有很好的接口。[2] 5.如果加入R的帮助邮件列表一,每天都可能会收到几十份关于R的邮件资讯。可以和全球一流的统计计算方面的专家讨论各种问题,可以说是全世界最大、最前沿的统计学家思维的聚集地.[2] R是基于S语言的一个GNU项目,所以也可以当作S语言的一种实现,通常用S语言编写的代码都可以不作修改的在R环境下运行。 R的语法是来自Scheme。R的使用与S-PLUS有很多类似之处,这两种语言有一定的兼容性。S-PLUS的使用手册,只要稍加修改就可作为R的使用手册。所以有人说:R,是S-PLUS的一个“克隆”。 但是请不要忘了:R是免费的(R is free)。R语言源代码托管在github,具体地址可以看参考资料。[3] 。 R语言的下载可以通过CRAN的镜像来查找。 R语言有域名为.cn的下载地址,有六个,其中两个由Datagurn,由 中国科学技术大学提供的。R语言Windows版,其中由两个下载地点是Datagurn和 USTC提供的。 三、stata Stata 是一套提供其使用者数据分析、数据管理以及绘制专业图表的完整及整合性统计软件。它提供许许多多功能,包含线性混合模型、均衡重复反复及多项式普罗比模式。用Stata绘制的统计图形相当精美。 新版本的STATA采用最具亲和力的窗口接口,使用者自行建立程序时,软件能提供具有直接命令式的语法。Stata提供完整的使用手册,包含统计样本建立、解释、模型与语法、文献等超过一万余页的出版品。 除此之外,Stata软件可以透过网络实时更新每天的最新功能,更可以得知世界各地的使用者对于STATA公司提出的问题与解决之道。使用者也可以透过Stata. Journal获得许许多多的相关讯息以及书籍介绍等。另外一个获取庞大资源的管道就是Statalist,它是一个独立的listserver,每月交替提供使用者超过1000个讯息以及50个程序。 四、PYTHON
对腾讯文档App进行产品分析