学习笔记:uglifyjs 混淆JavaScript
安装 sudo npm install uglify-js -g -g 全局安装 简单使用 uglifyjs 文件1 文件2 文件3 -c -m -o 输出文件 # 例如 uglifyjs a.js b.js c.js -c -m -o result.js -c 压缩输入文件(删除空白字符,注释等,而非常见的zip压缩) -m 混淆符号,这个是轻量的混淆,把长符号替换成端符号 -o 输出文件
安装 sudo npm install uglify-js -g -g 全局安装 简单使用 uglifyjs 文件1 文件2 文件3 -c -m -o 输出文件 # 例如 uglifyjs a.js b.js c.js -c -m -o result.js -c 压缩输入文件(删除空白字符,注释等,而非常见的zip压缩) -m 混淆符号,这个是轻量的混淆,把长符号替换成端符号 -o 输出文件
本文谷歌翻译. 正文 为程序生命周期中的特定事件建立了配置基准,并有助于程序的“获取程序基准”(APB)的绩效部分。 总体技术基准汇总到APB中,并包含以下配置基准: A Configuration Baseline is established for specific events in a programs life-cycle and contributes to the performance portion of a program’s Acquisition Program Baseline (APB). The overall Technical Baseline rolls up into the APB and consists of the following configuration baselines: 功能基准(Functional Baseline) 定义所需的系统功能,以描述整个系统的功能和接口特性,并进行验证以证明实现了这些指定功能特性。 该基准来自功能开发文档(CDD),通常包括整个系统的详细功能性能规范以及验证和验证总体系统性能所需的测试。 通常在系统功能审查(SFR)中建立功能基线并将其置于配置控制之下。 通常使用系统验证审查(SVR)和/或功能配置审核(FCA)对其进行验证。 Definition of the required system functionality describing functional and interface characteristics of the overall system, and the verification required to demonstrate the achievement of those specified functional characteristics. This baseline is derived from the Capability Development Document (CDD) and normally includes a detailed functional performance specification for the overall system and the tests necessary to verify and validate overall system performance. ...
JavaScript 原生中默认是没有 Console 对象,这是宿主对象提供的内置对象。 在webview中已经内置实现了,但是在JSCore这样的JS引擎中没有实现相关功能,因此为了前端同学调试方便和代码可移植性,有必要手动实现一个。 大体的实现思路如下: 注入全局的日志打印函数 我们可以注入一个全局的日志打印函数,假设名字叫做 NativePrint,然后创建Console对象,将Console对象的日志输出全部转发到这个 NativePrint 上。 NativePrint 接收两个参数,一个是日志类型,一个日志内容. iOS JSContext示例 JSContext * context = [JSContext new]; context[@"NativePrint"] = ^(NSString *logType , id logContext) { //打印输出 } Android V8示例 import com.eclipsesource.v8.V8; JavaVoidCallback callback = new JavaVoidCallback() { @Override public void invoke(final V8Object receiver, final V8Array parameters) { //解析parameters ,打印输出 } } V8 runtime = V8.createV8Runtime(); runtime.registerJavaMethod(callback, "NativePrint"); 注入Console对象 可变参数 对于JavaScript的方法来说,都有一个 arguments 参数列表(列表名字就是arguments),所以我们可以定义可变参数函数 javascript代码 注入NativePrint方法后,我们再注入一个全局的Console对象, 例如 console = { default:this, __Stringformat : function (values) { function __toString(s) { if (s === null || s === undefined) { return ""; } return s.toString(); } if (values.length == 0) { return ""; } else if (values.length == 1) { return __toString(values[0]); } index = 0; return values[0].replace(/%([a-zA-Z_])/g, function (match) { index = index +1; if (values.length > index) { return __toString(values[index]); } else { return ""; } }); }, info : function () { ffpd_log("info",this.__Stringformat(arguments)); }, warn : function () { ffpd_log("warn",this.__Stringformat(arguments)); }, //其他Console方法 }; 使用示例 ...
我曾经以为理所当然应该知道的事,而如今的一些程序员却一脸茫然。 先声明,我本人对Java没有偏见。 起因是这样的,同事拿着一段Java代码给我看,咨询下啥啥功能的事。我便细细观摩,看到关于读写文件的代码–将文件以字符串形式读到内存中。 看了会儿,我说:“这块有点瑕疵,没有指定文本的编码格式” 他说:“什么编码?以前也这么写的,运行起来没有问题。” ……(后续交流省略)….. 从我近年来和多位从事移动开发的程序员接触来看,我的感触就是移动互联网发展太快了,以至于他们完美的错过了这个行业很基础的知识灌溉—-或者忙着写业务了,或者手中正翻看xx天速成、包教包会的书,或者忙着追各种吹牛x的黑科技了, 好了,抱怨了一通,我转回正题。为什么要指定文本的编码格式?这事儿要从上世纪的蛮荒时代说起。 百花齐放 我们都知道,计算机的中储存以字节(8比特)为单位,人们阅读的文本在计算机存储都是一堆字节,而不是什么“世界你好,hello world”之类的可阅读文本。 为了解码这些字节,必须按照一定的规范将文本映射为计算机可以储存的字节。最早的可知晓的规范就是非常著名的ASCII编码,比如 0x30 代表字符 0, 0x41 代表字符 A 等等 ASCII编码,全称为美国信息交换标准代码, 在1967年作为规范标准发布,主要用来表示现代英文的编码约定(可以理解,那时计算机的主导是美国,到现在美国也是引领者),只定义了128个字符。 随着计算机的发展,越来越多的国家和地区使用计算机,自然因为语言不同,也有了制定适合自己国家和地区的文本编码了,诸如ISO系列,ibm系列,Windows系列,像中文的big-5,gb系列等, 详细请参考 这里,闲聊一句,上世纪80、90年代BP寻呼机,支持汉显和不支持汉显的价格有时能差一倍。 当编码多了,最大的问题是不同编码之间无法相互兼容,只有程序员能明白这其中的苦楚;若还是不明白,问问微软在上世纪是如何在各个国家和地区适配多语言的。 Unicode一统 文本编码不能相互兼容,这为软件行业的发展、互联网的推广带来了很大的麻烦,统一字符编码势在必行。最终统一的结果也就是今天大家看到的Unicode— 是由一个名为 Unicode 学术学会(Unicode Consortium)的机构制订的字符编码系统,支持现今世界各种不同语言的书面文本的交换、处理及显示。该编码于1990年开始研发,1994年正式公布,最新版本是2019年5月7日的Unicode 12.1.0(这段摘自百度百科)。 字符集和编码 这里单独说下字符集和编码的关系。 平时我们交流时,很少说字符集,通常都是Unicode编码、GB2312编码,UTF8之类的。 严谨的来说,包括Unicode、ASCII、GB2312在内的编码规范,其实分为两部分:字符集、编码方式。 字符集,指的是该规范收录了哪些字符,可以称之为字符的集合。例如,ASCII收录了数字、大小写英文字母、一些常用的符号和一些控制打印的字符;GBK2312收录包括ASCII在内的符号,以及常用的汉字和符号,还收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。 编码方式,指将收录的字符如何映射到计算机中的字节存储。简单来说,ASCII是单字节编码,为每一个收录的字符分配一个字节的数值表示,比如 0x30 代表字符 0, 0x41 代表字符 A。 GBK2312是双字节编码,为每一个收录的字符分配两个字节的数值表示。 UTF8,是Unicode字符集的一种编码方式,变长字节; UTF16,是Unicode字符集的一种编码方式,两个字节(不考虑Java中的字符代理对情况);另外,考虑到网络传输,UTF16还要区分大小端(大小尾)。两个数字 0xFFFE,0xFEFF,估计还是有人能看懂的。 UTF32,是Unicode字符集的一种编码方式,四个字节; UTF7,有谁听说过吗?是Unicode字符集的一种编码方式,变长字节。 另外,强烈建议在大部分场景使用UTF8编码方式,这是真正的万国编码。 为什么要指定文本编码 答:因为鬼知道我不指定编码,软件会怎么解码文本? 联通为什么干不过移动 答:微软记事本告诉你https://www.iteye.com/blog/mfkvfn-1703414 在windows操作系统中,新建一个文本文件,用词本打开,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是个乱码!而输入移去就不会有问题。 据说这就是联通之所以拼不过移动的原因。 Windows NT(Windows 2000及以上)版本的记事本 ,亦默认安装于Windows 2000和Windows XP中,可以侦查到缺乏字节序标记的Unicode文件。这个功能由一个Windows API提供,名为IsTextUnicode() 。但是,这个功能是不完美的,副作用是一些小写字体的ASCII文字,会错误判断为UTF-16。 在2006年5月18日,有报道称,对于一个含有类似"this app can break"这样短语的文档(甚至是类似"aaaa aaa aaa aaaaa"的简单短语),记事本会将其打开并显示为Unicode二进制文本。如果安装了相关中文字体则会显示二进制码所对应的汉字。造成这个错误的字符串可能形如“4个字母+空格+3个字母+空格+3个字母+空格+5个字母 ”,或者“4个字母+空格+5个字母+空格+5个字母+空格+5个字母 ”,并且文档末尾没有换行符。有人认为这是一个复活节彩蛋 ,但事实并非如此。还有人认为这是由于记事本的Unicode的检测算法所引起。 这个问题已在Windows Vista版本的Notepad中被修复。 但是,记事本还有一个问题,就是用ANSI保存的文档有时会被误认为Unicode。如在记事本中输入“联通 ”并保存,再次打开的时候会显示乱码,目前尚未被修复。
通过读取png图像文件的头信息 #include "stdio.h" namespace { class CFileStream { public: CFileStream (FILE *fs):m_fs(fs) {} ~CFileStream() { fclose(m_fs); } inline operator FILE*() { return m_fs; } inline operator bool() { return m_fs != 0; } private: FILE *m_fs; }; inline unsigned long Convert4char( unsigned char c[4]) //网络端字节序 { unsigned long n = ((unsigned long)c[0]) << 24; n += ((unsigned long)c[1]) << 16; n += ((unsigned long)c[2]) << 8; n += ((unsigned long)c[3]); return n; } } #define png_signature_len 8 //png文件签名 #define png_chunk_len_len 4 //idhr长度信息 #define png_chunk_type_len 4 //ihdr类型码 #define png_ihdr_data_len 13 //ihdr数据 + (BOOL)imageSizeFromPNGFile:(NSString *)pngFile size:(CGSize *)size; { if (!pngFile || !size) { return NO; } CFileStream fs = fopen([pngFile UTF8String], "rb"); if (!fs) { return NO; } unsigned char buf[png_signature_len+png_chunk_len_len+png_chunk_type_len+png_ihdr_data_len]; if (sizeof(buf) != fread(buf, 1, sizeof(buf), fs)) { return NO; } //校验文件签名 if ( memcmp(buf, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", png_signature_len) != 0 ) { return NO; } //校验ihdr长度 if (memcmp(buf + png_signature_len, "\x00\x00\x00\x0d", png_chunk_len_len) != 0) { return NO; } //校验ihdr类型码 if (memcmp(buf + png_signature_len +png_chunk_len_len, "IHDR", png_chunk_len_len) != 0) { return NO; } size->width = Convert4char(buf + png_signature_len+png_chunk_len_len+png_chunk_type_len ); size->height = Convert4char(buf + png_signature_len+png_chunk_len_len+png_chunk_type_len+4); return YES; } #undef png_signature_len #undef png_chunk_len_len #undef png_chunk_type_len #undef png_ihdr_data_len
动态创建一个类,NewClass ,继承自NSObject Class newClass = objc_allocateClassPair([NSObject class], "NewClass", 0); //向运行时注册这个类 objc_registerClassPair(newClass); //从运行时销毁这个类 objc_disposeClassPair(newClass);
集成 在Android Studio的Android工程中,需要在build.gradle文件内容里添加依赖指令,然后gradle构建就会自动化集成J2V8引擎 dependencies { implementation 'com.eclipsesource.j2v8:j2v8:5.0.103@aar' } J2V8的最新版本,可以在marven仓库中查看 https://mvnrepository.com/artifact/com.eclipsesource.j2v8/j2v8 使用示例 示例摘自https://eclipsesource.com/blogs/tutorials/getting-started-with-j2v8/ import com.eclipsesource.v8.V8; public static void main(String[] args) { V8 runtime = V8.createV8Runtime(); int result = runtime.executeIntegerScript("" + "var hello = 'hello, ';\n" + "var world = 'world!';\n" + "hello.concat(world).length;\n"); System.out.println(result); runtime.release(); } 访问JavaScript对象(Object) 假设有这样一段JS脚本 var jsobj = {}; jsobj.hello = "world"; 在J2V8中可以直接访问jsobj对象 import com.eclipsesource.v8.V8; public static void main(String[] args) { V8 runtime = V8.createV8Runtime(); runtime.executeVoidScript("" + "var jsobj = {};\n" + "jsobj.hello = 'world';\n"); // 访问jsobj的属性 V8Object jsobj = runtime.getObject("jsobj"); System.out.println(jsobj.getString("hello")); jsobj.release(); runtime.release(); } 需要注意, V8Object 需要自己手动释放 ...
NSOpenPanel控件 - (void)p_selectFileDialog:(void(^)(NSString* filePath))block { NSOpenPanel* panel = [NSOpenPanel openPanel]; [panel setCanChooseDirectories:NO]; [panel setAllowsMultipleSelection:NO]; [panel setMessage:@"提示语"]; // Display the panel attached to the document's window. [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){ if (result == NSModalResponseOK) { //点击确定后的代码 block(panel.URL.path); } else { block(nil); } }]; }
AES加密几个要点 对称加密(Symmetry Crypto) 加密和解密的钥匙是同一把—-加密方和解密方拥有相同的密钥(音yue,四声)。 密钥(key) 任意数据(不一定非得字符串),长度常见为128比特、192比特、256比特,也有支持512比特的算法库 初始化向量(IV) 这不是AES算法标准强制要求的,是一种增加AES破解难度的手段。IV和密钥共同参与加密和解密运算。IV长度固定为128比特。 加密块(block) 每次加密的块长度都是128比特;输入和输出长度相同,考虑补全模式的情况下,输出的最大长度 = 输入长度+128比特 加密模式 是指当需要加密的源数据长度大于128比特时,加密块和加密块之间的运算模式。 常见的有 CBC密码分组链接模式、ECB电码本模式(不推荐)、CTR计算器模式、CFB密码反馈模式、OFB输出反馈模式。 补全模式模式(padding) 因为AES一个加密块为16字节,当源数据的最后一个块不足16字节时,需要手动补全为16字节。 一般使用PKCS7模式,手动补全N个N,N为不足的字节数。 例如,最后一个块为 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 需要补6个字节,那么就是6个6 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x10 0x06 0x06 0x06 0x06 0x06 0x06 EVP AES 加密 #include "openssl/crypto.h" #include "openssl/aes.h" #include "openssl/evp.h" //引入c++的string,作为buffer使用 #include <string> //std::string 作为返回值其实可以右值优化的。 std::string encrypt(std::string &data , std::string &key ,std::string &iv) { //这里应该做必要的参数校验,如检查key和iv长度 //指定算法模式 EVP_CIPHER *ciper = NULL; switch (data.size()) { case 128 / 8: ciper = EVP_aes_128_cbc();break; case 192 / 8: ciper = EVP_aes_192_cbc();break; case 256 / 8: ciper = EVP_aes_256_cbc();break; default:return "需要做一些错误处理"; } //初始化ctx EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); //指定加密算法及key和iv int ret = EVP_EncryptInit_ex(ctx, ciper, NULL, (unsigned char *)key.c_str(), (unsigned char *)iv.c_str()); if(ret != 1) {//EVP_EncryptInit_ex failed EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } // 设置padding EVP框架默认使用的就是PKCS7 EVP_CIPHER_CTX_set_padding(ctx, 1); std::string buffer; buffer.append(0,AES_BLOCK_SIZE + data.size()); int mlen = 0; //进行加密操作 ret = EVP_EncryptUpdate(ctx, (unsigned char *)buffer.c_str(), &mlen, (unsigned char *)data.c_str(),(int)buffer.size()); if(ret != 1) { EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } int flen = 0; //结束加密操作 ret = EVP_EncryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &flen); if(ret != 1) { EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } EVP_CIPHER_CTX_free(ctx); buffer.resize(mlen + flen); return buffer; } EVP AES 解密 std::string decrypt(std::string &data , std::string &key ,std::string &iv) { //这里应该做必要的参数校验,如检查key和iv长度 //指定算法模式 EVP_CIPHER *ciper = NULL; switch (data.size()) { case 128 / 8: ciper = EVP_aes_128_cbc();break; case 192 / 8: ciper = EVP_aes_192_cbc();break; case 256 / 8: ciper = EVP_aes_256_cbc();break; default:return "需要做一些错误处理"; } //初始化ctx EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); //指定加密算法及key和iv int ret = EVP_DecryptInit_ex(ctx, ciper, NULL, (unsigned char *)key.c_str(), (unsigned char *)iv.c_str()); if(ret != 1) {//EVP_EncryptInit_ex failed EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } // 设置padding功能 EVP框架默认使用的就是PKCS7 EVP_CIPHER_CTX_set_padding(ctx, 1); std::string buffer; buffer.append(0,data.size()); int mlen = 0; //进行解密操作 ret = EVP_DecryptUpdate(ctx, (unsigned char *)buffer.c_str(), &mlen, (unsigned char *)data.c_str(),(int) data.size()); if(ret != 1) { EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } int flen = 0; //结束解密操作 ret = EVP_DecryptFinal_ex(ctx, (unsigned char *)buffer.c_str()+mlen, &flen); if(ret != 1) { EVP_CIPHER_CTX_free(ctx); return "需要做一些错误处理"; } EVP_CIPHER_CTX_free(ctx); buffer.resize(mlen + flen); return buffer; }
[[NSProcessInfo processInfo] systemUptime]; 或者 #include <mach/mach.h> #include <mach/mach_time.h> long long tm = mach_absolute_time(); static mach_timebase_info_data_t sTimebaseInfo; if ( sTimebaseInfo.denom == 0 ) //静态整型变量初始化时默认为0 { mach_timebase_info(&sTimebaseInfo); } return tm * sTimebaseInfo.numer / sTimebaseInfo.denom / (1000*1000);