分类目录归档:程序设计语言

ChakraCore Var数据类型指针疑惑

我最近看ChakraCore的源码做CVE分析的时候,一直不知道为什么Object Array能存储所有类型的对象。对于Native Value,它在高16位打Tag直接存进void * ,对于Object Pointer,它在void * 存入原封不动的指针。判断的时候,用SHR右移48位,看剩下的高位是否为0,若不为0,就是Tagged Native Value,否则就是Object Pointer。

今天分析CVE的时候突然想明白了48位是怎么定出来的了。因为x86_64现在的Virtual Address Size是48位。而且还有一个原因是,x86用户态的Canonical VM Address高16位是0000h开头。换个架构,这玩意貌似就不适用了。也没准随着Arch发展一下,VA Size增大一些,ChakraCore就彻底倒闭了。

注:微软不支持,应该已经倒闭了。

论文笔记:Fuzzing JavaScript Engines with Aspect-preserving Mutation

简介

模糊测试技术(Fuzzing)是现今最具有可实施性的Bug查找技术。它被广泛应用在真实世界中的复杂程序中。

模糊测试器(Fuzzer)主要分为两类,分别称为生成性的模糊测试器(Generative Fuzzer)和变异性的模糊测试器(Mutational Fuzzer):Generative Fuzzer利用相应编程语言的语料库(Corpus)中已经分拆好的代码块,通过语言的文法或预先定义的规则将它们装拼起来作为种子文件。Mutational Fuzzer通过更改已有的PoC或测试样例中的部分代码来产生新的种子文件。

但作者认为,这两种类型的方法都不能充分利用高质量的语料库。因为上述两种方法不但没有良好的保持一些作为PoC的固有属性,反而为了代码覆盖率的因素破坏了它们。

为了解决上述问题,本文的作者创新性地提出了“方位保持变异”(Aspect-preserving mutation)的方法来保持PoC的固有属性。该理论结合了Generative和Mutational的特性,对于其中的一大部分代码保留,一小部分代码通过Generative的方法进行生成。生成时,注意维持其中的固有属性。其中,固有属性包括两种:结构保持(Structure preservation)和类型保持(Type preservation)。为了达到这一目的,作者对已有的语料库文件进行建模,形成带类型的抽象语法树(Typed Abstract Syntax Tree)模型。在语法树的基础上施加相应的变异。

作者将该理论运用进了他们最先进的JavaScript Fuzzer,DIE。他们利用DIE对ChakraCore,JavaScriptCore和V8进行了Fuzz。结果产生了48个Bug,有12个分配了对应的CVE编号。

动机

当下的Fuzzer不能够充分的探索JavaScript引擎的深层次代码及其中存在的Bug,主要的原因如下:
1、搜索空间过大:当下的Fuzzer为了触发内存损坏(Memory Corruption)错误,一味的追求代码覆盖率。但对于现今的JS引擎,这种简单错误已经减少。更多的是深层次的逻辑错误。
2、不能充分的利用已有的语料库:能够触发JIT的代码都需要有一定的前置条件,并且这些前置条件有相当多的共同点。例如,执行次数较多的for循环会触发JIT。其它类型的Fuzzer没有很好的保持这些前置条件,从而降低了产生Crash的机会。

主要方法及工作流程

Structure-preserving mutation: 保持程序的主要结构,例如控制流。这样能够增加保留触发JIT的前置条件的可能性。
Type-preserving mutation: 通过对语料库文件建模,形成带类型的抽象语法树。每次对子树对应的代码段进行更改时,始终保持它们的返回类型或值类型基本一致,以减少出现语法或类型等错误的可能性。

Workflow:
前处理部分:首先对原始的种子文件送入插桩后的引擎进行动态类型分析,得到对应的类型分析。结合静态文法识别出的AST,产生对应的Typed-AST并送入语料库。
种子生成部分:变异引擎(Mutation Engine)从语料库中选取Typed-AST加以修改,形成变异的Type-AST,再由该AST反推回JS文件,送入Fuzzing平台。
执行/反馈部分:由分布式Fuzzing系统进行执行,产生覆盖率反馈和崩溃报告。其中覆盖率反馈闭环传递至语料库,崩溃报告发送给工程师。

评估结果

1、DIE可以在现实世界的JS引擎中找到新的Bug,并且还不少。
2、本篇论文提出的“方位保持”在找到Bug方面起到了关键作用。一是“方位”(即固有属性)确实能很好的触发Bug,二是DIE确实保持了语料库中相应程序片段的“方位”。
3、DIE相对其他类型的Fuzzer,能够较好地产生在语法和语义上正确的JS程序。
4、在输入空间(代码覆盖率)及Crash产生率上,DIE相对其他Fuzzer都有优势。

展望

1、种子优先级:因为种子的质量不同,在做种子的变异时,可以对种子实现优先级的排队。
2、规则优先级:可以根据测试需要,对程序中Generative的部分的产生规则也实现优先级的排队。
3、“方位”的标注:利用人工标注代码中“方位”的特性。
4、“方位”在其它语言的推广:“方位”的思想对于其他语言也是通用的,可以将这一思想拓展到其他语言上编写Fuzzer。

引用

[0] 论文链接:https://ieeexplore.ieee.org/document/9152648/

DOSBox-8086Assembly

最近我们学校在上8086汇编课程,需要写汇编程序。而Masm套件自带的debug调试程序是命令行的,不很好用。于是我在网上搜索了一下好用的8086汇编调试器,搜到了Turbo Debugger,经过试用。发现非常好用,带有GUI界面,非常人性化。于是就想把它和DOSBox集成到一起,制作一个输入源代码文件,即可自动开始调试的程序。经过努力,我做出了这个套件。我把它称作:DOSBox-8086Assembly。

继续阅读

C++指针

仅做保留参考个人使用,谁要是能看懂,那就是C++大神了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<iostream>
#include<typeinfo>
using namespace std;
char s[2010][2010];
int * func1(int a, int b) { return 0; }
int *(*func)(int, int) = func1;
int main() {
    cout << typeid(func1).name() << endl;
    cout << typeid(func).name() << endl;
    auto ptr = &s;
    cout << typeid(&ptr).name() << " " << sizeof(&ptr) << " " << (int)(&ptr + 1) - (int)(&ptr) << endl;
    cout << typeid(ptr).name() << " " << sizeof(ptr) << " " << (int)(ptr + 1) - (int)(ptr) << endl;
    cout << typeid(&s).name() << " " << sizeof(&s) << " " << (int)(&s + 1) - (int)(&s) << endl;
    cout << typeid(s).name() << " " << sizeof(s) << " " << (int)(s + 1) - (int)(s) << endl;
    cout << typeid(*s).name() << " " << sizeof(*s) << " " << (int)(*s + 1) - (int)(*s) << endl;
    cout << typeid(&s[0]).name() << " " << sizeof(&s[0]) << " " << (int)(&s[0] + 1) - (int)(&s[0]) << endl;
    cout << typeid(s[0]).name() << " " << sizeof(s[0]) << " " << (int)(s[0] + 1) - (int)(s[0]) << endl;
    cout << typeid(*s[0]).name() << " " << sizeof(*s[0]) << endl;
    cout << typeid(&s[0][0]).name() << " " << sizeof(&s[0][0]) << " " << (int)(&s[0][0] + 1) - (int)(&s[0][0]) << endl;
    cout << typeid(s[0][0]).name() << " " << sizeof(s[0][0]) << endl;
}

输出结果(找一个好点的编译器,别用g++,输出的Typeinfo没法看):

1
2
3
4
5
6
7
8
9
10
11
12
int * __cdecl(int,int)
int * (__cdecl*)(int,int)
char (* *)[2010][2010] 4 4
char (*)[2010][2010] 4 4040100
char (*)[2010][2010] 4 4040100
char [2010][2010] 4040100 2010
char [2010] 2010 1
char (*)[2010] 4 2010
char [2010] 2010 1
char 1
char * 4 1
char 1

总结:对某类型做sizeof运算,返回的是本类型本身的大小;对某类型指针做加减操作,数值为n,是对其绝对地址加减:对该指针解除引用后的类型的sizeof运算的数值乘以n。

洛谷 谁拿了最多奖学金

这题本身没啥好说的,非常简单,要说的是C++的一个特性。
这个题写的比较复杂,其实不用这么多空间,也不要排序,直接线性处理就行了。但是我写题写习惯了,又接着搞排序,就出了这么个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<bits/stdc++.h>
using namespace std;
int n;
struct stu{
    string name;
    int fs,cs;
    char sl,wp;
    int an;
    int money;
    stu(){
        money=0;
    }
    bool operator < (const stu& s2){
        return money>=s2.money;
    }
}stus[105];
int sum=0;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>stus[i].name>>stus[i].fs>>stus[i].cs>>stus[i].sl>>stus[i].wp>>stus[i].an;
    for(int i=1;i<=n;i++){
        if(stus[i].fs>80&&stus[i].an>=1)stus[i].money+=8000;
        if(stus[i].fs>85&&stus[i].cs>80)stus[i].money+=4000;
        if(stus[i].fs>90)stus[i].money+=2000;
        if(stus[i].fs>85&&stus[i].wp=='Y')stus[i].money+=1000;
        if(stus[i].cs>80&&stus[i].sl=='Y')stus[i].money+=850;
        sum+=stus[i].money;
    }
    sort(stus+1,stus+n+1);
    cout<<stus[1].name<<endl;
    cout<<stus[1].money<<endl;
    cout<<sum;
}

问题就出在比较的>=号上。查找了资料(地址http://blog.sina.com.cn/s/blog_532f6e8f01014c7y.html),我没细看,总结出来就是sort的cmp不能用带=号的。这个问题我最后就用stable_sort解决了。好用。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<iostream>
#include<algorithm>
using namespace std;
int n;
struct stu{
    string name;
    int fs,cs;
    char sl,wp;
    int an;
    int money;
    bool operator < (const stu& s2) const{
        return money>s2.money;
    }
}stus[205];
int sum1=0;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>stus[i].name>>stus[i].fs>>stus[i].cs>>stus[i].sl>>stus[i].wp>>stus[i].an;
    }
    for(int i=1;i<=n;i++){
        if(stus[i].fs>80&&stus[i].an>=1)stus[i].money+=8000;
        if(stus[i].fs>85&&stus[i].cs>80)stus[i].money+=4000;
        if(stus[i].fs>90)stus[i].money+=2000;
        if(stus[i].fs>85&&stus[i].wp=='Y')stus[i].money+=1000;
        if(stus[i].cs>80&&stus[i].sl=='Y')stus[i].money+=850;
        sum1+=stus[i].money;
    }
    stable_sort(stus+1,stus+n+1);
    cout<<stus[1].name<<endl;
    cout<<stus[1].money<<endl;
    cout<<sum1;
}

简易python socket通信

Server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#coding=utf-8
import socket
HOST='127.0.0.1'
PORT=52314
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
while 1:
    conn,addr=s.accept()
    print 'The client on %s is connecting the server.' % str(addr)
    while 1:
        data=conn.recv(1024)
        if data=="\q":
            print 'The client is going to offline.'
            conn.close()
            break
        else:
            print data
conn.close()
s.close()

Client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#coding=utf-8
import socket
HOST = '127.0.0.1'
PORT = 52314
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    while 1:
        cmd = raw_input()
        if cmd == "quit":
            print 'Bye!'
            s.sendall("\q")
            break
        s.sendall(cmd)
finally:
    s.sendall("\q")
    s.close()

PAT乙级21道总结

时光飞逝转眼就要开学了,两天之后;然而我还有一堆作业,把这几天努力的成果贴到网上,分享一下。这些代码是在PAT乙级网站上所有点AC的代码,现在贴上来。
AC的题目序号:1001-1016 1019 1022 1023 1026 1060
挑着好做的先做这么多。。
下个假期继续努力,明天数据结构就出图了,还要看图,就不刷PAT了。
下载链接在下边……
继续阅读

翱翔计划冬令营的结束和2048

翱翔计划冬令营终于结束啦,我学到了一些数据结构,除此之外,我还写了好多好多手机小游戏呢。其中最最最最让我自豪的是我竟然写了一个C++2048的控制台版(Console Program)我好自豪啊!已经发到Github上开源了,才270多行,我好自豪!其中有变量有指针有引用有过程声明,代码重用性很高……我好自豪啊……
代码Github地址: 继续阅读