Different program representations and their applications

Graphical representation can help researchers in all research fields and can depict the program features better than the textual source code. In this article, we want to review different graphs that are extracted from source code and represent programs.
A graph consists of some nodes and some edges that connect nodes to each other, these edges show different relationships between nodes.
In general, we can split graphs into two groups [1], flow graph, and dependence graph. in the following, we will review different models of them and at the end, we can see which is the most useful one.

Abstract syntax tree

The first graph that can represent the program is the Abstract syntax tree or AST.
AST is a representation of the syntax of program source code but not in detail, more details are in Concrete syntax tree( Parse tree ). As shown in the example below, its nodes and edges show the structure of the code.
Although it doesn’t have all detailed information about the source code, it resolves ambiguity form code.

AST is the result of the syntax analysis phase of a compiler and is used in program analysis. In order to transforme programs to each other, AST is generated and used.
This is the example code to show the result of different graphs on it:

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
#include<stdio.h>
int main()
{
int num,copy_of_num,sum=0,rem;


printf("\nEnter a number:");
scanf("%d",&num);


copy_of_num = num;


while (num != 0)
{
rem = num % 10;
sum = sum + (rem*rem*rem);
num = num / 10;
}

if(copy_of_num == sum)
printf("\n%d is an Armstrong Number",copy_of_num);
else
printf("\n%d is not an Armstrong Number",copy_of_num);
return(0);
}

For generating AST, you can use Clang and it generates the AST with this command :

1
clang -Xclang -ast-dump -fsyntax-only test.cc

This file is the result of above command; download it and see it with this command, colorfully:

1
echo -ne $(cat output.txt | sed  's/$/\\n/' | sed 's/ /\\a /g')

This AST Graph is related to the above sample code:

AST


Call graph and Control flow graph

The Call Graph shows the relationship between subroutines and functions in a program. its nodes show different procedures, and edges show which function calls the other one. Based on the call graph we can find some lines of code that are never called [1] and analyze the general flow of data in the program. Call graphs can also be used to detect code injection attacks or anomalies of program execution. So the call graph gives an inter-procedural view of a program.

The control flow graph or CFG provides more details about each path, it is an intra-procedural view of a subroutine. Each node represents a basic block of code and each edge shows a control flow transfer. A basic block is a set of consecutive statements. Compared with AST, CFGs have less redundancy but from AST we can get the source code easier.

This is the CFG corresponding to our example code, which is generated using clang; for more detail about clang read this blog post:
CFG

Each basic block in CFG contains some statements, we can split them in each node and this will be the result for CFG above. This CFG can show dependencies better that basic block.

CFG


Program dependence graph

By aggregating the data dependence graph(DDG) and the control dependence graph(CDG), we will have a program dependence graph(PDG). Nodes are basic blocks and edges are control and data dependence edges. In CDG, edges represent direct control dependence. In the Data dependence graph, if a variable v which is declared in statement X, is used in statement Y and there is a path from X to Y in the program that doesn’t define v, there will be an edge [1] from X to Y.

For more detail about PDG and a method to build it, see this lecture.

Now, This is the PDG for the previous algorithm:

red edges are control dependence and green edges are data dependence.

PDG

Recent conferences and graph representation

Top conferences can show the usage of the above graph representation in different research areas. To this end, I review related articles in these recent conferences: USENIX 2020 & 2019, NDSS 2020 & 2019, S&P 2020 & 2019, ICSE 2020 & 2019 and CSS 2019. Here is a bar chart to show the distribution of graph usage in their articles that are based on C/C++ programs. As it shows, CFG is the most used graph because although the graph is not very large, it has useful information about code and can illustrate the code well.

plot

and these are their titles:

AST

  1. MVP: Detecting Vulnerabilities using Patch-Enhanced Vulnerability Signatures USENIX 2020
  2. Automating Patching of Vulnerable Open-Source Software Versions in Application Binaries NDSS 2019
  3. Impact Analysis of Cross-Project Bugs on Software Ecosystems ICSE 2020
  4. A Novel Neural Source Code Representation based on Abstract Syntax Tree ICSE 2019
  5. Superion: Grammar-Aware Greybox Fuzzing ICSE 2019

CFG

  1. AURORA: Statistical Crash Analysis for Automated Root Cause Explanation USENIX 2020
  2. FuzzGen: Automatic Fuzzer Generation USENIX 2020
  3. ParmeSan: Sanitizer-guided Greybox Fuzzing USENIX 2020
  4. SpecFuzz: Bringing Spectre-type vulnerabilities to the surface USENIX 2020
  5. FuzzGuard: Filtering out Unreachable Inputs in Directed Grey-box Fuzzing through Deep Learning USENIX 2020
  6. MUZZ: Thread-aware Grey-box Fuzzing for Effective Bug Hunting in Multithreaded Programs USENIX 2020
  7. GREYONE: Data Flow Sensitive Fuzzing USENIX 2020
  8. GRIMOIRE: Synthesizing Structure while Fuzzing USENIX 2019
  9. DEEPBINDIFF: Learning Program-Wide Code Representations for Binary Diffing NDSS 2020
  10. Not All Coverage Measurements Are Equal: Fuzzing by Coverage Accounting for Input Prioritization NDSS 2020
  11. Send Hardest Problems My Way: Probabilistic Path Prioritization for Hybrid Fuzzing NDSS 2019
  12. Matryoshka: Fuzzing Deeply Nested Branches CSS 2019
  13. PANGOLIN: Incremental Hybrid Fuzzing with Polyhedral Path Abstraction S&P 2020
  14. SAVIOR: Towards Bug-Driven Hybrid Testing S&P 2020
  15. Full-Speed Fuzzing: Reducing Fuzzing Overhead through Coverage-Guided Tracing S&P 2019
  16. Iodine: Fast Dynamic Taint Tracking Using Rollback-free Optimistic Hybrid Analysis S&P 2019
  17. A Large-Scale Empirical Study on Vulnerability Distribution within Projects and the Lessons Learned ICSE 2020

PDG

  1. MVP: Detecting Vulnerabilities using Patch-Enhanced Vulnerability Signatures USENIX 2020
  2. FuzzGen: Automatic Fuzzer Generation USENIX 2020
  3. REDQUEEN: Fuzzing with Input-to-State Correspondence NDSS 2019
  4. Practical Fault Detection in Puppet Programs ICSE 2020

Call graph

  1. KOOBE: Towards Facilitating Exploit Generation of Kernel Out-Of-Bounds Write Vulnerabilities USENIX 2020
  2. Temporal System Call Specialization for Attack Surface Reduction USENIX 2020
  3. FuzzGuard: Filtering out Unreachable Inputs in Directed Grey-box Fuzzing through Deep Learning USENIX 2020
  4. MUZZ: Thread-aware Grey-box Fuzzing for Effective Bug Hunting in Multithreaded Programs USENIX 2020
  5. Precisely Characterizing Security Impact in a Flood of Patches via Symbolic Rule Comparison NDSS 2020
  6. Iodine: Fast Dynamic Taint Tracking Using Rollback-free Optimistic Hybrid Analysis S&P 2019
  7. A Large-Scale Empirical Study on Vulnerability Distribution within Projects and the Lessons Learned ICSE 2020
  8. Practical Fault Detection in Puppet Programs ICSE 2020

Code property graph

  1. LEOPARD: Identifying Vulnerable Code for Vulnerability Assessment through Program MetricsTechnical Track ICSE 2019

Use-flow graph,value-flow graph

  1. SMOKE: Scalable Path-Sensitive Memory Leak Detection for Millions of Lines of Code ICSE 2019

References

  1. Arora, V., Bhatia, R.K. and Singh, M., 2012. Evaluation of flow graph and dependence graphs for program representation. International Journal of Computer Applications, 56(14).

Post by: Maryam Ebrahimzadeh

Generating source-level Control Flow Graph using Clang 4.0

Introduction

I needed to find all possible paths a program could traverse during its execution. I also needed to modify a few of the basic blocks in the given source code. Therefore, IR or something similar wasn’t suitable.
I was looking through different tools for a few days to find the proper one but I found nothing useful. Finally, I decided to read up on Clang.

Clang is a C/C++/Objective-C compiler front-end. It is a sub-project of LLVM and uses LLVM for code optimization and back-end support. Figure 1 shows how source code, clang, LLVM IR and LLVM are connected. You can read more about this project on LLVM Website and LLVM Wikipedia.

Figure 1: Relation between Clang and LLVM

Clang is not only a compiler frontend with many options, but also a very powerful C++ library for having control over the abstract syntax tree (AST), automated editing source code, etc. I initially read about a method in Clang’s library, buildCFG, and I came to the conclusion that Clang is my guardian angel. : ) I found out that it is possible to write a new tool using Clang’s library.

In the rest of this post, I will explain step-by-step what I did to achieve what I need.

Using Clang as a library

Clang provides different interfaces that we can choose from to write a clang-tool. We will use LibTooling which is an unstable and backward-incompatible C++ API and gives us full control over the AST.

It may seem counter intuitive to write an unstable and backward-incompatible API, however:

One could argue that instability is a design goal.

—Eli Bendersky

So we can compromise backward-compatibility to keep moving forward, to refactor our design as needed, and to be up to date in general.

We are going to write our clang-tool using Clang-4.0 and this tool might not be compatible with more recent versions (e.g. Clang-8).

How to write this tool?

The first step in generating a Control Flow Graph (CFG) for each function is to answer this question: Where are function declarations in the code? Since Clang is a compiler front-end, it generates and uses AST. To answer the question, we can search in the AST to find some nodes representing function declarations. Clang holds AST nodes in ASTContext which is defined in ASTContext.h

But what is our interface to read this AST? Clang’s library has prepared an abstract interface, ASTConsumer, which is defined in ASTConsumer.h. We have to define a new object that inherits ASTConsumer and overrides a fews methods of it (and probably adds a few variables) to read AST in our desired way.

ASTConsumer has many methods for reading the AST. We are using HandleTranslationUnit(clang::ASTContext&) which is invoked when AST of each translation unit is parsed. This method is empty and we must override it. We could probably also use HandelTopLevelDecl(clang::DeclGroupRef) which is invoked at every top-level declaration but I did not test this method.

So far, we know that we have to define a new object that inherits ASTConsumer and overrides HandleTranslationUnit(clang::ASTContext&). In our case, this method should look for function declarations.
Clang has two other classes: clang::ast_matchers::MatchFinder and clang::ast_matchers::MatchFinder::MatchCallback. The first one, checks if there is a “matching node“ in the context or not, and the second is a “callback“ object which is called when the “matching node” that is registered for it is successfully found in the AST.

So, an instance of clang::ast_matchers::MatchFinder (call it “Finder“) searches for the specified nodes and upon finding a “matching node”, it calls an instance of the corresponding “callback” object. In fact, all “callback” objects have a method named run(const clang::ast_matchers::MatchFinder::MatchResult&). “Finder” calls this method and passes the information of the “matching node” as an argument with type const clang::ast_matchers::MatchFinder::MatchResult& to it.

How to specify some nodes? This document is a reference for all ASTMatchers. So we can specify function declaration nodes as below:

1
2
3
4
5
const auto matching_node =  
clang::ast_matchers::functionDecl(isExpansionInMainFile()).bind("fn");
/*`bind()` binds a function declaration node to an ID.
Callback object can distinguish results(matched nodes) by this ID.
Here, all "functionDecl" nodes are bound to ID="fn".*/

Up here, we have this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyCallback : public clang::ast_matchers::MatchFinder::MatchCallback {
MyCallback(){}
void run(const clang::ast_matchers::MatchFinder::MatchResult &Result){
// do something with this result
}
};

class MyConsumer : public clang::ASTConsumer {
public:
explicit MyConsumer() : handler() {
const auto matching_node = clang::ast_matchers::functionDecl(isExpansionInMainFile()).bind("fn");
match_finder.addMatcher(matching_node, &handler);
}
void HandleTranslationUnit(clang::ASTContext& ctx) {
match_finder.matchAST(ctx);
}
private:
MyCallback handler;
clang::ast_matchers::MatchFinder match_finder;
};

and we can implement run as below:

1
2
3
4
5
6
7
8
9
10
11
void run(const clang::ast_matchers::MatchFinder::MatchResult &Result){
const auto* Function = Result.Nodes.getNodeAs<clang::FunctionDecl>("fn");
const auto CFG = clang::CFG::buildCFG(Function,
Function->getBody(),
Result.Context,
clang::CFG::BuildOptions());
for (const auto* blk : *CFG){
blk->dump(); // Prints Basic Blocks.
// do something more.
}
}

Putting it all together, we have:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Clang includes
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/ASTMatchers/ASTMatchers.h>
#include <clang/Analysis/CFG.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/LangOptions.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendAction.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>

// LLVM includes
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/raw_ostream.h>

class MyCallback : public clang::ast_matchers::MatchFinder::MatchCallback {
public:
MyCallback(){}
void run(const clang::ast_matchers::MatchFinder::MatchResult &Result){
const auto* Function = Result.Nodes.getNodeAs<clang::FunctionDecl>("fn");
const auto CFG = clang::CFG::buildCFG(Function,
Function->getBody(),
Result.Context,
clang::CFG::BuildOptions());
for (const auto* blk : *CFG){
blk->dump(); // Prints Basic Blocks.
// do something more.
}
}
};

class MyConsumer : public clang::ASTConsumer {
public:
explicit MyConsumer() : handler() {
const auto matching_node = clang::ast_matchers::functionDecl(clang::ast_matchers::isExpansionInMainFile()).bind("fn");
match_finder.addMatcher(matching_node, &handler);
}
void HandleTranslationUnit(clang::ASTContext& ctx) {
match_finder.matchAST(ctx);
}
private:
MyCallback handler;
clang::ast_matchers::MatchFinder match_finder;
};

class MyFrontendAction : public clang::ASTFrontendAction {
public:
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance&, llvm::StringRef) override {
return std::make_unique<MyConsumer>();
}
};

struct ToolFactory : public clang::tooling::FrontendActionFactory {
clang::FrontendAction* create() override {
return new MyFrontendAction();
}
};

int main(int argc, const char **argv) {
auto CFGCategory = llvm::cl::OptionCategory("CFG");
clang::tooling::CommonOptionsParser OptionsParser(argc, argv, CFGCategory);
clang::tooling::ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
// run the Clang Tool, creating a new FrontendAction.
return Tool.run(new ToolFactory);
}

To build this tool (with name cfg.cpp), use this Makefile:

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
35
36
37
TARGET := cfg
HEADERS := -isystem `llvm-config-4.0 --includedir`
WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter
CXXFLAGS := $(WARNINGS) -std=c++14 -fno-exceptions -fno-rtti -O3 -Os
LDFLAGS := `llvm-config-4.0 --ldflags`

CLANG_LIBS := \
-lclangFrontendTool \
-lclangRewriteFrontend \
-lclangDynamicASTMatchers \
-lclangToolingCore \
-lclangTooling \
-lclangFrontend \
-lclangASTMatchers \
-lclangParse \
-lclangDriver \
-lclangSerialization \
-lclangRewrite \
-lclangSema \
-lclangEdit \
-lclangAnalysis \
-lclangAST \
-lclangLex \
-lclangBasic

LIBS := $(CLANG_LIBS) `llvm-config-4.0 --libs --system-libs`

all: cfg

.phony: clean
.phony: run

clean:
rm $(TARGET) || echo -n ""

cfg: $(TARGET).cpp
$(CXX) $(HEADERS) $(LDFLAGS) $(CXXFLAGS) $(TARGET).cpp $(LIBS) -o $(TARGET)

If you have not installed LLVM-4 and Clang-4 on your system, use this:

1
sudo apt install llvm-4.0 llvm-4.0-dev clang-4.0 libclang-4.0-dev python-clang-4.0

then simply:

1
2
cd path/to/file
make

finally, use this tool:

1
./cfg path/to/target/code.cpp --

Example

As an example, you can take a look at the code below:

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
void print_hello(void){
printf("Hello\n");
}

void print_good(void){
printf("Goodbye\n");
}

void print_bad(void){
printf("Oh no!\n");
}
void darkerthandark(void){
printf("DARK\n");
}

int main(){
int i;
int a = 10;

if (a < 10)
print_hello();
if (0)
print_good();
if (1)
print_bad();

for ( i = 0 , a = 3 ; i < 99 ; i++){
darkerthandark();
}
return 0;

}

The output for the main function is:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
[B0 (EXIT)]
Preds (1): B1


[B1]
1: return 0;
Preds (1): B4
Succs (1): B0


[B2]
1: i++
Preds (1): B3
Succs (1): B4


[B3]
1: darkerthandark()
Preds (1): B4
Succs (1): B2


[B4]
1: i < 99
T: for (...; [B4.1]; ...)
Preds (2): B2 B5
Succs (2): B3 B1


[B5]
1: i = 0
2: a = 3
3: ... , [B5.2]
Preds (2): B6 B7(Unreachable)
Succs (1): B4


[B6]
1: print_bad()
Preds (1): B7
Succs (1): B5


[B7]
1: 1
T: if [B7.1]
Preds (2): B8 B9
Succs (2): B6 B5(Unreachable)


[B8]
1: print_good()
Preds (1): B9(Unreachable)
Succs (1): B7


[B9]
1: 0
T: if [B9.1]
Preds (2): B10 B11
Succs (2): B8(Unreachable) B7


[B10]
1: print_hello()
Preds (1): B11
Succs (1): B9


[B11]
1: int i;
2: int a = 10;
3: a < 10
T: if [B11.3]
Preds (1): B12
Succs (2): B10 B9


[B12 (ENTRY)]
Succs (1): B11

Conclusion

I was initially just searching for a proper tool to generate the CFG of any function. Finally, by using Clang’s LibTooling, not only did I succeed to generate the CFG, but also it was possible for me to manipulate basic blocks easily.

As a result, after working with Clang, I was enthusiastic to try developing different clang-tools using the AST. The reason was that Clang has a very well-designed architecture. Also, the comments written in Clang’s source code are very useful and instructive. Above all, Clang is a very powerful tool for having control over the AST. After learning some basics, you can write many different tools and this will cause a very enjoyable feeling! :)

Thanks to Peter Goldsborough who helped me to write my own clang-tool by his useful talk at C++Now 2017.

[1], LLVM for Grad Students

References

[1], Clang’s source code!

[2], Clang’s documentation

[3], Peter Goldsborough’s talk at C++Now 2017.

[4], Kevin Boos’s blog post.

Post by: Hossein Moghaddas

A look at the V8 engine

drawing

Intro

Disclaimer: The V8 engine is a huge project and inevitably complex. It takes lots of time to go through everything and cannot be done in a reasonably sized blogpost, thus here I am just scraping the surface. Hopefully I can show you why I find trekking through V8 a delightful journey.

V8 engine is the javascript engine powering, among other stuff, chrome browser and nodeJS. NodeJS for example, adds low-level IO, and an event-loop on top of V8. Due to V8 being almost omnipresent given the wide adaptation of Chrome, Chromium-based browsers and NodeJS makes it a coveted target for security exploitations. Recently even Microsoft ditched their own engine which powered Edge and Chakra, for Chromium.


What lies underneath?

Chrome (and V8) has been a massive success. After the browser war which led to the fall of Netscape and dominance of Internet Explorer, the browser landscape became dull and the rapid innovations died out. And then came Chrome in 2008, and the rest, they say, is history (An overview of the rise of Chrome, by a former Micrsoft employee). From an engineering point of view, it is my go-to example of software done right. Fulfilling the arduous task of making javascript blazing fast, given how it is designed (e.g. being untyped), requires great effort. The solution, V8, is thus composed of many components and with complexity rising, so do the prospects of having vulnerabilites and V8 has had it’s fair share of CVEs.

Lets get familiar with some V8 lingo: Orinoco is the garbage collector. Liftoff is the web assembly(WASM) compiler, then comes the duo making V8 fastest engine on the planet: Ignition and Turbofan. So why is V8 so fast? Great credit goes to Ignition and Turbofan, Ignition is an interpreter and Turbofan is a compiler. So when you bring up a web page you want to see it loaded fast, so you JIT (compile, just in time) later when you keep running a JS function though, you ask yourself, isn’t it better that instead of running some VM bytecodes to execute this function over and over again, I had some faster, machine code instead? And that is the trick they do, if some code is deemed ‘hot’ and you keep calling it it is optimized by being compiled to machine code via Turbofan but the buck doesn’t stop here: V8 gather type feedback to speed it up. Recall that JS is an untyped language, so it makes it painfull to execute simple addition in JS: is it an addition of numbers? Of strings? You just do not know and thus you have to generate many additional code in cases that the typing is not clear. The type feedback guesses types so that after you call a function with a number as the argument after a few times, it hints Turbofan that the argument is going to be a number. What happens if this intuition proves wrong and you call it with a string? What happens is called deoptimization, the generated specialized machine code is thrown away, and again Ignition takes the reins.

Further more every piece is crafted with performance in mind. For example the scanner (the part in charge of transforming an stream of characters into tokens) makes tables containing flags for each ASCII character to flag whether each character can be start of an id, or continuation of an id so that on consuming each character we can verify whether we’re still in side an id, or that it uses perfect hashing on the length of each keyword and the first two characters to tell if an identifier is a keyword or not.

The source

The required tools to build V8 is git (which you probably have) and depot-tools (git is included in depot-tools on Windows). Then you execute “gclient“ and it updates. By this point, you should be able to do this as depot-tools directory should be in your path. Then cd into the directory you wish and execute “fetch v8“ and grab a coffee, this will take some time. Now, before buliding, executing gclient sync will get you build dependencies and you will be ready to build. tools/dev/gm.py x64.release builds V8 and you can access the built binaries at the subdirectory tools/dev/out/x64.release. Go on, take a look at the contents of this directory.
icudtl.dat for example is the bundled ICU: International Components for Unicode data. If you open this file using an editor and choose Unicode encoding you can see e.g. names of countries in your language of choice [here Iran can be seen in Farsi].



Inside icudtl.dat

There are 2 directories here, gen which as the name suggests contains auto generated stuff. You can find header and source files here (e.g. generated by torque), among ninja metadata and cache files. Besides that there are some dll and lib files (or equivalent shared libraries in *nix systems).
Reading through the source code and trying to make out how things fit together is good practice for C++ enthusiasts as the code conforms to good practices (well, mostly) but as the project is huge, one cannot just swallow it all in one bite rather you can take a subsystem of the project, say the scanner, and first focus on that and later after the smaller pieces are worked out look into how they integrate to make the greater picture. For example, in the scanner, to define the types of tokens X Macro are used which is a cool trick leveraging the preprocessor that I find to be underrated and less used.
Now onwards to the executables.

Executables

mksnapshot.exe

This tool takes in a js file and outputs a cpp source file (by default snapshot.cc). But what snapshot? What is it doing? The js file you put in is initialization code for an instance of V8 engine, and the idea is that to improve start-up times, you can “capture” the state of V8 engine into a snapshot using this tool. So as it can be guessed you can also pass optional V8 arguments to this tool to customize the snapshot you get. Afterwards you just copy the generated snapshot to /src directory and build again. So to recap, normally V8 would create the stuff it needs on-the-fly on the heap (loading math libraries for example) with snapshot you put it in a blob and later the deserialize it back. Way faster! Now that we are here let’s also talk about isolates. An isolate is an isolated instance of V8 engine: meaning that objects of an isolate for example, should not be used in another isolate, each isolate has it’s own separate independent state. This technology for sandboxing has gained traction and has been, for example used by cloudflare and is about taking the idea of containers to the extreme: with containers we set out to take VMs a step towards more performance, by sharing the OS kernel across containers instead of everyone bringing their OS kernel with themselves. Now with an isolate, we share more stuff [here, the code of the V8 engine, doing all the heavy work of a JS runtime] across isolate instances. Here is how you make an isolate instance from an snapshot file (which you have made using mksnapshot):

1
2
3
4
5
6
7
8
9
10
11
int len = 0;    // for storing length of file
byte* snapshot = ReadBytes(snap_filename, &len);
v8::Isolate* v8_isolate = v8::Isolate::New();; // our isolate instance
if (snapshot) // make sure file successfully read
{
SnapshotData data(Vector<const byte>(str, len));
Deserializer decoder(&snapshot_data);
v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Isolate::Scope isolate_scope(v8_isolate);
isolate->Init(&decoder);
}

torque.exe

To understand torque, we should first understand V8’s notion of builtins. Not to be confused with the related but distince entity that is javascript’s builtin objects, in V8 builtin is a bunch of code which can be executed at runtime by the VM. Now to make one, you have 4 options. 1: You can use machine code. That sounds cool right? And in fact it is, but it has a drawback which is the issue of portability. For every machine type (x86 / arm / …) you have to implement your builtin, which makes it time-consuming and prone to more errors, maintenance and debugging burden. Despite this, for the sake of performance this method was used but then came our method 2: CSA: Code Stub Assembler which is a platform-agnostic assembler, a thin wrapper over assembly, which provides means to do multi-platform assembly code. Later came Torque as a means to replace CSA, with the same idea, torque is a DSL(Domain Specific Language) with syntax quite similar to TypeScript. Actually torque is interoperable with CSA, and in fact under the hood, instead of generating assembly code directly, it generates C++ code interfacing with CSA to do its bidding. So the pipeline is like this, you make a torque file (say, hello.tq) then feed it to torque and you get (in /gen directory) a C++ file hello-from-dsl-gen.cc now our old friend mksnapshot, builds all the builtins (inlcuding our newly made hello). They are baked into the snapshot and ready for use.

d8.exe

d8 is like what irb is to Ruby, it is where you can play with V8 and javascript and poke and prod around the engine. It is a minimal shell envinronment for debugging, with options like –trace-opt-verbose that traces when optimization of a function is done (Ignitition sends through to Turbofan to make faster code) with a similar one for deoptimization. You can also make your own custom runtime functions, and pass –allow-natives-syntax to d8 so that you can try them out in d8. You have to declare your function in src/runtime/runtime.h using the RUNTIME_FUNCTION macro and then put the source file with the implementatio in src/runtime/ directory.

There is so many things you can learn from V8, and so many ways to have fun with it. The V8 docs has good material, I also recommend this post by Franziska Hinkelmann regarding the bytecode. Once you begin to make sense of V8, you will also be ready to grasp SpiderMonkey as the concepts are quite similar, for example the idea of optimizing hotcode and using type feedback can be seen in Mozilla flavor, named tracing jit .

Post by: Iman Hosseini

Installing the Capstone disassembler (with commentary)

The premise

I came across this tool Capstone as I wanted to make a simple tool for binary analysis and have some fun with homegrown tools. One module I implemented first is a parser which reads through a PE (.exe) file and parses the header to find where the sections, tables, and other metadata are in the file; And then knowing where the sections are, the data is, and the code is. I was thinking: let’s find the basic blocks, plot the cfg? What would that need: to understand the binary code. It looks simple: just make a big hashmap mapping bytes to the mnemonics and operators right? Until I realized this actually is not that simple, the ISA we’re talking is not small and by the way I found Capstone which does what I needed here BUT also it is doing it faster and supports all architectures, with some helper functions out-of-the-box as well: i.e. point it to the beginning of a code section, and it disassembles all the way.

So Capstone is a framework for disassembly: it helps you dissasemble bytes into human readable instruction for [almost] any ISA on [almost] any platform. You can view the full features on their website, but the bottom line is this tool is ubiquitous in reversing tools, you can view 402 projects in which Capstone has been used on their website among them is radare2. which you might recall from another post

Another feature is that there are bindings for many languages: Go, Js, .NET (C#), Java, Python, Haskell, Rust, PHP and more. This means you can easily integrate it into whatever else you are doing in any language, a big bonus. In this tutorial lets first get it to work on Windows with C (this is the toughest option. If you want to use it in js, there’s no hitch: just get the minified js and you can use it; couldn’t be easier!)

Spending few hours stuck trying to get Capstone playing nice with Visual Studio, led me to learn more about how C Runtime works in the Windows world, and this is something useful for other Visual Studio endeavours as well, say you want to do a project whith OpenGL and want glm, freeglut you will see a lot of this. (Or any other C related project really) Also another benefit of looking into Capstone’s repository is that Capstone is a well-crafted tool, writers say the best way to learn writing is to read good prose, similarly Capstone conforms to good coding practices and looking into the code is instructive, and also it is a relatively big C project working on linux, windows and mac and it is also beneficial to check it out if you are interested in making a multi-platform C project, a class in using CMake. One of the features of Capstone that you can build your customized version of Capstone, trimming the features you do not need, this again is a pattern which is very useful in various projects.

Windows - Staring MSVC in the eye

For windows, the problem is building C using MSVC has its quirks. Trying out the sample test from the website, we set up a new console project in Visual Studio and then, of course, we need to tell Visual Studio how to actually use Capstone we need to tell it somehow, where to look for headers and stuff.

The windows distributions when extracted, includes a folder called include where the headers are, and there are .lib files and a .dll and cstool.exe which is a commandline tool. You can do (this is right from the readme file at cstool directory):

The _-d_ option shows details. Pretty cool for a quick query. Moving on, .lib files contain the IAT (Import Address Table) which tells the linker where to look for different functions in the .dll which includes the actual code, and is loaded at runtime. So if no .lib will spew out errors from the linker that I need a function but I cannot find it, and no .dll means it tries to find the .dll (and fails) or if there is a .dll but it is not compatible from that .lib tries to find a function at the address from the IAT but would hit some weird errors this time.

First we tell Visual Studio (I am on 2017, but instructions would be similar) where that include folder is located [my project is named caps]: Go to Project > caps Properties…

As it can be seen you just head to C/C++ > General there is a field for Additional Include Directories and you add the directory of the include file (containing the relevant headers). (don’t forget the separation delimiter _;_) Now we put capstone.dll and the .lib in the project directory. By default it looks for dll files there, but you can also specify it at the VC++ directories tab, and not put the dll in project directory: you might want to be fancy and put the .lib and .dll files in seperate folders and not the root directory of the project. You can also just put them anywhere, but it’s better if they aren’t outside your project folder i.e. imagine you want to release the code.

And finally we specify what .lib files we need using: Linker > Input > Additional Dependencies

It should now build without error right? That’s what I thought but I got a ton of errors, errors like LNK 2001 unresolved external symbol vsnprintf. After searching the names showing up here, I realized the linker is having problems even with memcpy, in linux these are all part of the in libc, the [shared] library for standard C. So we probably have a .lib problem here. TL;DR to have C runtime, turns out we need to add these .lib files as well (the same way as before): _ucrt.lib; libcvruntime.lib; libcmt.lib; _

Adding these should fix the problem. You can see some details here, but basically ucrt.lib is the Universal CRT: back in the old days it used to be different but in Visual Studio 2015 Microsoft refactored CRT and standard C library, POSIX extensions and some microsoft-specific macros and variables were moved into UCRT and some compiler-specific (as opposed to the Universal in UCRT) were moved to libvcruntime.lib and also libcmt.lib (LIBC[D].LIB, LIBCMT[D].LIB, and MSVCRT[D].LIB are all similar the MT is for MultiThreaded, the D is for DLL versions, which are not statically linked and thus also require the corresponding DLL). You can view which symbols are in which by omitting that lib and trying to build:

The better way though is to use Microsoft’s DUMPBIN tool to see info on each library. As an example, some runtime check functions (you can spot them as they have RTC in their names) are in libcmt.lib , and the famous free, malloc, strlen, … we know and love, are in ucrt.lib. And if you see weird long symbols, particularly with atsigns in the name that is due to name mangling.

Linux - Goodbye .dll ; hello .so

In linux things are easier really, fastest way is to just build from source: get the github repo and (as the instructions say):

1
2
$ sudo ./make.sh 
$ sudo ./make.sh install

And you are good to go. If you do prefer not to build from source for some reason, then use the packeged versions:

1
$ sudo apt-get install libcapstone-dev

This is for development and gets you libcapstone3 as a dependency but you can just apt-get libcapstone3 directly if you wish. At the time of writing, the capstone website is outdated and instructs you to apt-get libcapstone2 but that package is now extinct (won’t find it) and you should try it with version 3. (If you build from soruce you are getting the latest, which is version 4)

There are examples, if you have got the repo from github, at capstone/tests/ and you can make and then try out the generated binaries. If you see the makefile there you will get an idea of how it works, but it is a bit complicated so if you are in a separata directory and just trying to compile your code, do this:

1
$ gcc test.c -lcapstone

The _-l[LIBRARY_NAME]_ switch tells the compiler (actually the linker, ld) that you are linking against [LIBRARY_NAME] (here capstone) library which you have installed. If you do not specify this option, you will not get into a problem with the header, gcc knows where to find the header but then it will spew errors. Comparing to windows, this is what happens in place of those .dll , .lib work we did. Using:

1
$ dpkg -L libcapstone3

You can view which directories are affected (-L switch is for list) and you can see that installation would put Capstone files in directories like /usr/share , /usr/lib , .. (one for headers, shared libraries, docs etc.) and so when you specify -lcapstone to gcc it looks for capstone.so or capstone.a in these directories. Slick!

Post by: Iman Hosseini

An excursion in evaluation of binary analysis tools

As outlined in a previous blog post, there are multiple tools for binary and source analysis. They are crafted with slightly different motivations and considerations by their respective developers and thus it is not trivial or well-defined to generally evaluate them against each other.

If we really want a comparative evaluation though, to have a meaningful one we need to identify a feature supported by all the tools under consideration, and generating callgraph is a baseline feature all tools support, and the idea is simple: the tool would analyze the code (be it binary or source code) and identify the functions and if a function foo can call bar, make an edge foo->bar in the callgraph.

The test program which I used to test, was just defining a bunch of functions which call each other. The main was empty, but it suffices as all it matters is the callgraph which is about how these defined functions call each other. And to then make that structured I generated hybercubes with them: for an N-hypercube, for 0 to 2^N - 1 name the functions as: name i = “f”+[binary representation of i] so for i = 2 we have f00, f01, f10, f11. Now treat each binary representation as coordinates in an N-dimensional space, each function would correspond to a vertex of a hypercube, for 2d its a regular square, and for 3d a (normal)cube. How are the vertices connected? Each two points are connected if their Hamming distance is 1 (i.e. they differ in only one coordinate).


FIG1. 10 dimensional graph, rendered using GraphStream



Hypercubes admit nice symmetries and are aesthetically pleasing but there is a downside: for our test we want to cover programs of different sizes, and we would fancy a way to cover different sizes as we want. With hypercubes we do not have a gauge, notice that ‘size’ here, would be the number of edges, and for a N-cube it is N^3, so we can get only programs of sizes 1, 8, 27, 64, … and so not only we are not making programs of arbitrary size but also the sizes aren’t even uniform, and the distance between possible program sizes diverge as N increases. The title image is a glimpse of one of the callgraphs generated by bap. It is very easy with bap:

1
$bap executable -dcfg > output.dot

Due to the symmetry of the hypercubes, it is very efficient to test the resulting callgraphs: if we have the correct number of edges, and each edge is between functions at Hamming distance 1, the callgraph is correct. But to have a better tunable measure for performance I generated programs using another model: a (n,p) program is a program with n functions, and for each function there is a probability p that it calls any other function => the expected number of edges is NN\P. Now we have two parameters to tune the size.

One measure of performance then would be the time it takes for a tool to make the callgraph. But time, is variable. We can take a number of trials and average over them to get a more stable measure, but still from system to system it would differ and also it depends at the state of the system at runtime. Valgrind is a tool which lets you profile machine instructions: the number of instructions does not depend on runtime, and much less on the system as for the same architecture, the same compiler would generate the same machine code.


FIG2. Radare2 takes linear instruction (/time) to find callgraph



FIG3. Radare2 vs BAP (Yellow), x: edge size | y: instuction count


For Radare2, as shown in FIG2, which is a plot of [y: number of edges - x: number of instructions] the number instructions (which roughly is itself, linearly related to time) increases linearly with the number of edges (each edge, is a function call, inside the body of another function) so it seems that the underlying implementation of Radare2 is O(N) -where N is the number of calls/edges-.

When comparing Radare2 with bap (FIG3), we see that even though they are both linear, radare2 is way faster; and for bap there is a threshold after which there is a bump in the slope. Also, rather peculiarly, if you feed bap very large (larger than 100 function) code you get false positives: bap detects functions which are not existent. We should be getting edges like: “ f12 -> f18 “ but we suddenly begin to get bogus ones too like: “ sub_4064ab” -> f308 “.

I tried various ansatzes to find out what is the reason behind this, (radare2 does not show this artifact) but it seems totally arbitrary: even the functions which are messed up, are not at the end/beginning i.e. out of 200 functions, f121 is messed up, f200 is fine. I discussed it with Ivan Gotovchits, the main developer of bap as well, and he said it’s just some false positive somehow, and maybe it’ll be fixed if I turn off byteweight, which didn’t fix it.

The code for the C code generator is available at:https://github.com/S4Lab/Benchmark-Utils

Post by: Iman Hosseini

Coffee in S4Lab

Photos by Parmida Vahdatnia

It is now roughly 8 months that I am part of the S4Lab and during this time I have learned about various qualities here that makes S4 great, and recently there has been a new addition which specifically I am very fond of: We’ve got a full stack coffee framework.

Grinding the beans in-house means that you get the aroma of coffee welcoming you to the lab and a fresh cup of coffee is the perfect beginning for a day of work. And if you are thinking decaf…

Honoré de Balzac, famous novelist and playwright, on coffee: “This coffee falls into your stomach, and straightway there is a general commotion. Ideas begin to move like the battalions of the Grand Army of the battlefield, and the battle takes place. Things remembered arrive at full gallop, ensuing to the wind. The light cavalry of comparisons deliver a magnificent deploying charge, the artillery of logic hurry up with their train and ammunition, the shafts of which start up like sharpshooters. Similes arise, the paper is covered with ink; for the struggle commences and is concluded with torrents of black water, just as a battle with powder.” Only for us, instead of similes it is data structures arising, and the instead of paper we have emacs. [Editorial Note: vim would have been/is a much better selection, than emacs]

Post by: Iman Hosseini

Automated Binary Analysis (a short intro)

Automated program analysis is the practice of analyzing computer programs using [other] programs, as opposed to code audits by a developer. The objective can be to find security vulnerabilities, to optimize, or to reverse engineer an obfuscated program and gain knowledge about its flow. The are benefits to this approach. It allows scalability to cater to the huge number of programs at large which would not be possible to audit “manually”. Code auditing is a skill that is not gained easily, so a developer good for the job doesn’t come cheap. Also, online and live monitoring of code might be a necessity.
Automated program analysis can be implemented at two levels: static analysis is concerned with analysis of code at compile time, without actually executing the program. And dynamic analysis is done with executing the program and considering the runtime as well. Also, the input program can be source code of the program, or the compiled binary. Each approach has its benefits and disadvantages. Inferring the callgraph of a program, tracking api-calls, and recovering control flow graph of the program can be among the tasks of analysis platforms.
A tool used for runtime analysis of programs is symbolic execution, which runs through the program assuming symbolic (rather than concrete) values for the variables to gain further knowledge about the flow of a program.

A concrete example


Trail of Bits sketches a way to detect heartbleed. It is based on a characterization of the vulnerability via calls to ntoh and hton which can taint a variable, then calling memcopy and passing a tainted value to it, without bound-checking.
To this end, they have used Clang Analyzer. As part of LLVM, there is a tool to do static analysis of programs: scan-bulid. To perform a custom analysis, everything goes into a C++ class and registers as a plugin. Here’s how the code looks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void NetworkTaintChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
const IdentifierInfo *ID = Call.getCalleeIdentifier();
if(ID == NULL) {
return;
}

if(ID->getName() == "ntohl" || ID->getName() == "ntohs") {
ProgramStateRef State = C.getState();
SymbolRef Sym = Call.getReturnValue().getAsSymbol();

if(Sym) {
ProgramStateRef newState = State->addTaint(Sym);
C.addTransition(newState);
}
}

Similarly, to check for function calls, we could have used BAP). In its original and preferred OCaml it looks like:

1
2
module CG = Graphs.Callgraph
module CFG = Graphs.Tid


This gives access to callgraph and cfg. Now imagine we wanted a function that will take the call graph cg, the target function, and the subroutine term sub, and return a sequence of calls that has a destination function, that reaches target in the call graph. BAP provides for us nifty methods.

1
2
3
4
5
6
7
8
9
10
11

let callsites cg target sub =
Term.enum blk_t sub |>
Seq.concat_map ~f:(fun blk ->
Term.enum jmp_t blk |> Seq.filter_map ~f:(fun j ->
match Jmp.kind j with
| Goto _ | Ret _ | Int (_,_) -> None
| Call dst -> match Call.target dst with
| Direct tid when reaches cg tid target ->
Some (Term.tid blk)
| _ -> None))

In a similar manner, every custom analysis is developed in an OCaml (or other bindings) file and then registered as a plugin to BAP. (instructions here)

So many tools!


There are also other tools built with different motivations in mind, among them angr , ROSE, radare2.
Radare2 is more suited for ctf, ROSE used to be source analysis and thus supports source analysis as well as binary and angr was used to make mechanical phish which won 3rd place at Darpa’s Cyber Grand Challenge. ROSE is developed in C++, and is fast and great for research, but when you want to work on small programs (like a ctf challenge) you’d rather take other options, like bap which is based on OCaml and you can use baptop which is a REPL environment that you can interactively run commands and play around with the binary.

The most recent work published using angr, is (USENIX Security ‘18) HeapHopper: Bringing Bounded Model Checking to Heap Implementation Security which leverages the tool to implement another tool called HeapHopper which inspects heap implementations for vulnerablities. The method has been proven to be successful on a ptmalloc vulnerability, and uses angr as it’s symbolic execution engine checking compiled programs, after attempted exploit, for security violations.

Post by: Iman Hosseini

S4Lab Walkthrough

What we do at S4Lab

The short version of our work is that we like the kind of magic that concerns software. That means while security is not mathematically provable and the world is full of smart programmers with cute programs, we want to show the weakness in software and systems (how cute a program can be?) and find ways to secure them.


Software Security

Researchers have introduced lots of program analysis methods over the last four decades. Initially, the primary goal of these methods was compiler optimization. With the emergence of malware, new dynamic approaches have been introduced for the sake of finding the malicious behavior that only appears at runtime.

In recent years with rising the cost that software bugs may cause, researchers used the available automatic program analysis methods to test programs and answer the question “Does a program have any bugs?”. Altough none of the methods answer this question entirely, the goal of the automatic program testing is identifying as many real bugs as possible with minimal user augmentation and measure/show their risk.
Here at S4lab, we want to answer the following questions:

  • What kind of magic reveals software bugs as much as possible?
  • Can we decide which part of the programs are more vulnerable?
  • Can we improve the magic to prove vulnerabilities?
  • How can we measure the risk each bug has?
    Traditionally the program analysis methods are categorized as follows:

Dimensions

If you want to get familiar with these approaches, we suggest the following references:


System Security

Although using secure software is essential, it is always possible that interactions between the different layer of the computing stack remain vulnerable. Therefore developing tools and methods to detect potential flaws in communication channels, i.e., kernel/user, kernel/virtualization layer, kernel/hardware layer, etc. is important.
To get familiar with this area we suggest reviewing the following papers:


Find what is wrong


Find what is wrong? (artwork by @wackyposters)

You see, but you do not observe. The distinction is clear. [Sherlock Holmes]

While our primary focus is software and system security, any new security-related problems may interest us, especially finding new and innovative ways to measure security or to show that there are flaws in software and system that we use in our everyday life. You should be curious enough to sense that there is something wrong about them, indeed you should observe carefully.
To get familiar with these topics we suggest the following references:

What you should do to join S4Lab

If we knew what it was we were doing, it would not be called research, would it? [Albert Einstein]

You should understand that security related fields are not as straightforward as shown in Hollywood movies. In most cases, we do not know what the next step is, and we are not sure if we can find a way to prove that security is broken. But that doesn’t mean we should stop trying.
You should be patient, ambitious, and determined enough to work at S4Lab,
If you find S4Lab suitable for your work, please follow the steps below and you will see how deep the rabbit hole goes.


Let us know what interests you more

Summarize 2 of papers we have suggested reviewing above, choose the ones that interest you more. The writing should be your own words and try to avoid using the paper sentences.
You can add any related data, possible open problems that you may find, or only focus on the papers.
Each summary should not be longer than 2 pages.


Prove that you are a hacker (i.e. problem solver)

Most hackers are young because young people tend to be adaptable. As long as you remain adaptable, you can always be a good hacker. [Emmanuel Goldstein]

Being a hacker means you do not leave a problem unsolved because it is written in Haskell.
Before joining S4Lab, you need to prove that you are a hacker, to do so, please answer the following questions:

  • Many websites expose their “.git” files, please show how it could be dangerous.
  • Imagine that we have 2**48 text files. Explain how can we find which files are the same.
  • Write a hello-world C program and explain how we can dump its binary code with radare2.

Please remember that you do not need to write very much, and try to solve each task as automatically as you can.


Stay tuned

Upload the requested data, on your public GitHub account and send us its URL.


You should love Git!

Post by: Solmaz Salimi

Top NDSS'18 Papers

It was some time ago that I read a post somewhere (really can’t remember where) with a simple question. What are the top papers which one should read from conferences every year in order to keep up to date with the latest and most important developments. This was an interesting and yet challenging question. Nevertheless, we (i.e. our research team) decided to review papers from the top4 security conferences in our regular weekly meetings and through a process select the top 5 papers from each conference.

How did we go about it?
This was our first try on the issue, so not much of a scientific approach! We started studying papers as they were presented from the first session and on. In every meeting we selected the top papers from the sessions reviewed, and then argued if they should be kept in a top 10 list, and if the top 10 list was full, if any papers should be removed from the list to make room for the new paper selected. At the end of the process, we were left with 10 papers for the whole conference, from which we argued and selected the top 5.

What is considered “TOP”?
“Top” is a subjective matter, and to make matters worse security is a very wide field with very different topics which require very different expertise. Over the sessions, it became clear that there were biases. For example if a topic was new for everyone, they would argue that it should be included in the “top” list, where as there may have been previous research on the topic that the students where unaware of. There was also bias on topic which everyone was more familiar with. In such cases the argument was that a major problem was solved(i.e. although the scope of the work was very narrow). So again, top is a subjective matter. But I believe that as time goes on, and we keep doing this for a few more conferences, this bias would be less of an issue as everyone would have seen more papers to compare with.

Was the process useful?
Most definitely. Although we did not cover every detail in the papers we read, but we did study current day problems which is are being addressed by researchers and the approach taken to tackle the problem. In fact as papers were reviewed from different sessions, students were exposed to different problems and solutions; Where the subject was very different from what the are researching on. I find this to be extremely important. Students usually get too focused on a specific topic, and they lose sight as to the bigger picture. In other words, such exercise is great in providing “breadth” to the student, in addition to the “depth” obtained as part of research on a specific topic.

Here are the Top5 selected papers from NDSS’18:

1- Superset Disassembly: Statically Rewriting x86 Binaries Without Heuristics. Erick Bauman (University of Texas at Dallas), Zhiqiang Lin (University of Texas at Dallas), and Kevin Hamlen (University of Texas at Dallas).
2- Face Flashing: a Secure Liveness Detection Protocol based on Light Reflections. Di Tang (Chinese University of Hong Kong), Zhe Zhou (Fudan University), Yinqian Zhang (Ohio State University), and Kehuan Zhang (Chinese University of Hong Kong).
3- Cloud Strife: Mitigating the Security Risks of Domain-Validated Certificates. Kevin Borgolte (UC Santa Barbara), Tobias Fiebig (TU Delft), Shuang Hao (UT Dallas), Christopher Kruegel (UC Santa Barbara), and Giovanni Vigna (UC Santa Barbara).
4- Device Pairing at the Touch of an Electrode. Marc Roeschlin (University of Oxford), Ivan Martinovic (University of Oxford), and Kasper B. Rasmussen (University of Oxford).
5- Settling Payments Fast and Private: Efficient Decentralized Routing for Path-Based Transactions. Stefanie Roos (University of Waterloo), Pedro Moreno-Sanchez (Purdue University), Aniket Kate (Purdue University), and Ian Goldberg (University of Waterloo).

Last but not least, we are always happy if we could get more people in the room arguing on the papers. So if you like to participate in the process for the next conference review please drop me an email.

Post by: Mehdi Kharrazi