 Good afternoon everybody. My name is Andrew, now at least, and I'm here to talk about Anger, which is a tool that we have developed to do static analysis and symbolic execution using VEX. Like I said, I am a researcher. I'm an undergraduate student at the University of California, Santa Barbara. We work in what we call the sec lab. We are, like most of the people in this room, interested in finding bugs in software, and because we are researchers, we are interested in publishing papers about finding bugs in software. The more automatic, the better in this case. And also, we are CTF players. CTF, as maybe some of you may know, is Captcha the Flag. It's a computer security game. It's fun, you know. It's about taking the security tasks and making them into fun challenges that you can solve for points, occasionally money. But what we really like to do, as all these different categories of people, is have some way to perform binary analysis tasks in useful modular, modularizable, abstracted ways. And to that end, we have developed a system called Anger. And Anger is, the tagline is, a highly modular Python framework that performs binary analysis using VEX as an intermediate representation. In fact, the name Anger is a pun on VEX because when something is vexing, it makes you angry. Probably half of our code base's name is pun-based. Oh, no, that's totally true. The graphical interface for Anger is called Anger Management. And so the idea of Anger is made of many interlocking parts which provide useful abstractions for analysis. So the point, so the first part of this presentation is going to be detailing the pile of abstract web fractions that we call Anger. So interlocking part one is Pyvex, which is effectively a FFI form functions interface wrapper around libvex. So this is the, this is the bread and butter of all of our further analysis that we'd like to be able to do. We would like to be able to run a line of Python and have out a Python object, which is the intermediate representation superblock, the IRSB, that contains the VEX IR code that is much more easily analyzed than just x86 bytes or armbytes or what have you. So the way that we've done this is there's a whole lot of hacking into libvex in order to actually get the IRSB object out and then we deep copy it into a set of Python classes that represent the internal VEX structs that are easy to work with in Python. So you can just drill into an IRSB and say, well, what's the third statements operation and what are its arguments, which are read temp and a constant statement. Oh, good. That's much better. There we go. And technically, this can be totally independent of libvex, the library, because we have an interface in which you can write lifters in pure Python and we've done this for AVR, MSP430 and BrainFuck. Yeah, no. So that's interlocking part number one, interlocking part number four is called Cinevex. Cinevex is jumping ahead a little, the actual symbolic execution that we do with IRSBs. So I'll explain what exactly symbolic execution is in the moment and how exactly it works. But for now, you just need to know that it takes the IRSBs that we have generated via Pyvex and executes them. But it technically supports execution from other interfaces that aren't vex. Cinevex has grown into a little bit of a misnomer as we've grown and expanded the library to support more things, but it's the first and the best supported and it's also in the name. So most importantly, if you're going to emulate IRSBs, you're going to need to emulate the effects of each of the kind of IR statements, expressions, operations, dirty calls and clean calls. But ultimately, the abstraction you got out of Cinevex is this concept of a simulated state, which is a representation of a program state at a given time. And the symbolic execution process is one that produces, given a state, any number of successors that could possibly result from executing that state. So once we get into the part, once we start thinking about executing things, we need to start thinking about the environment in which we execute things. So we need to start thinking about how do we model memory, how do we model registers? Vex has sort of decided the answers to those questions for us. We have a flat memory space and a flat register file. But other than that, you need to start providing, well, what happens when you hit the IJK sys and you need to emulate a sys call? What happens when, how do you actually model those sys calls and their events symbolically and et cetera? So one of the things that we use to make this work whatsoever is this module called Clarify and our locking part number two. So Valgrind and its friends will want to use vex and emulate these things and all the registers that will be integers. But what we want is we not want not integers, but symbolic bit vectors, which are effectively variables that can be built up into trees. And then you can end up with ASTs of just variables and values and operations. And then you can reason about, well, what if there were a constraint saying that this value must be greater than this value? And you just say that that is an assertion over the current program state. Then once that assertion is in place, you can use an S&T solver such as Z3 in order to reason about additional values that therefore must be a certain value given this constraint. So Clarify is the abstraction layer that allows us to reason about bit vectors, as well as integers, as well as any number of domains that we will sometimes choose to use for static analysis. So as a brief introduction here, let's talk about what the actual process of symbolic execution looks like. So we're going to show you how symbolic execution executes a program and what we can do with that. And these slides are stolen from every single other presentation about anger ever. So pretend for a moment that we have this code slide so you don't even have to pretend. There it is. So we're going to start execution up here, the blue line. And we're going to start with a sort of blank slate, blank state that contains sort of the, we'll say is that, well, we don't know what X is yet, and there's no constraints on this state yet, but we do know our instruction pointer is there. So when we tick forward, we're going to, I should have said, okay, so when I say X is question marks, what I actually mean is X is a symbolic value, that is, X is user input. And we don't know how to have any idea. We don't have any conception of what that value could be. So we'll just create a symbol X and say that is X. Then as we tick execution forward, we will hit that branch statement. And there are two possible things, places that the CPU could jump to after that instruction. It could either jump to here or it could jump to here. And in symbolic execution, we take both. So this initial state produces two successor states, state AA and state AB. In it, X, we still have no conception about what the actual value of X is, but we do now have a constraint, an assertion over the domain of values X may take on. That is, in this state AA, we know that X must be less than 10, and in state AB, X must be greater than or equal to 10. And so then, yeah, so the process of, the process of Cinevex, the symbolic execution, is effectively computing that this constraint is extracting the idea of this constraint from the code and placing it in the actual state. So if we just sort of continue the example, we are now going to take the state AB, because that's the one that's getting us closer to the U win, because we're trying to win here. That's what we're here to do. So then state AB is going to further branch on the second if statement, and it's going to add the constraint, again, add the constraints on the state X is less than 100, X is greater than or equal to 100. And so now we can say that that state ABA is the state that ends up being at the U win spot, and we can tell that. So therefore, we just invoke a constraint solver on the value of X, given those variables. And we end up with, well, there is a possible value of X that could, and it does, cause the program to take that path. So that's symbolic execution. That's the goal here. So as sort of a side note, the third interlocking part, and I'm very out of order list of interlocking parts, is a binary load that we implemented for the Angular project. It's called clay, stands for clay loads everything. It's very complicated. Talking about it is not at all within the scope of the presentation, but it ought to be mentioned since it is important. It takes, it does the job of a dynamic loader. It takes a library and executables and turns them into an address space. I did most of the work on that. It's very hard. Don't ever try to do that. So the interlocking part number five, the last part, there's an infinite number of interlocking parts, but let's pretend that there's a finite number, so there's five of them, is anger, the actual top level control module. So this takes all these abstractions and puts them together into a control interface called a project, which allows convenient access to symbolic execution and also several built-in analyses that do a lot of common tasks, like control flow, graphic recovery, data flow analysis, et cetera, et cetera. And additionally, it has a knowledge base that allows analyses to store artifacts of truth that is found about the program and isn't analyzing. So here in this example, this is just copied from our homepage. It inputs anger, loads a sort of fake firmware binary for where it performs a control flow graph analysis on it, and now the project's knowledge base has been populated with a listing of all the functions in the binary. For example, here's the entry point, here's the main function, here's two functions conveniently called accepted and rejected, et cetera, et cetera. And then we create an abstraction called a path group, which is a control interface for symbolic execution, and tell the path groups to just blindly tick forward until it finds any state that lives at this address, which is conveniently... I'm pretty sure this hex address is the same as this accepted state address in hex. So we just search for a state at that address, and then when we find one of those states, we ask for a concretization of standard input, and it tells us the password for this firmware. So that's that example. That's just the firmware example that's the tour de force of here's anger doing static analysis and symbolic execution really fast. That was a lot. Anger is big and complicated, but a lot of care has been taken to make it a stack of useful abstractions so that any part of the binary analysis process can be easily instrumented. And what can we do with anger? Well, we can analyze a lot of things. We can do symbolic execution as I've shown. We can do analysis that ship with anger, control flow graph, binary diffing, disassembly, backward slicing, data flow analysis, value set analysis, et cetera. We wrote and then published on a static binary rewriters that can do reassembly of binary programs with instrumentation. There's some limited ability to type inference. We can do symbolically assisted fuzzing, which is very good for bug finding. We can do automatic exploit generation. And also if you're us, we have anger to build a huge system to play an automated form, to play CTF automatically and win third place in the world's first automated CTF called the Cyber Grand Challenge. Oh, God, I need to talk about the CGC now. So... How much time do I have? I've only used 15 minutes. Okay, I can talk about the CGC. So in the United States of America, there's this part of the government called DARPA, and their job is to throw a lot of money at researchers to do research that they want to do. So one of the things they've done recently is they decided, well, we want the state of the art for binary analysis and auto exploitation, et cetera, to be advanced. So they said, hey, researchers in the United States, we want you to build a machine that can play against other machines totally autonomously playing the standard game that we call Captcha the Flag. Now, this is sort of a format that DARPA has done in the past. DARPA, their original grand challenge was for self-driving cars. You may have heard of that. The grand challenge was let's take this established human sport of car racing and say, can we build AIs to do the same thing? And so the Cyber Grand Challenge is the same thing but for the game of CTF. So this ultimately turned into a huge engineering effort of putting a lot of trauma associated with the four months of horrifying development that went into the CGC. But ultimately, we built a system called the Mechanical Fish to use anger at its core to analyze binaries, find vulnerabilities, and then patch those vulnerabilities, turn total vulnerabilities into exploits and then launch those exploits against a series of opponents on a closed network and win us a million and a half dollars. That was pretty good. Yeah, this is all open source. The anger is totally open source. All of the mechanical fish is also open source, I should mention. It's just sort of sitting up on GitHub. If you wanted to kick-start a robot uprising, it's probably a good place to start. So there's some of the analysis capabilities of anger, but what you can also do is build a community. That's what we've done, because a lot of people seem to be using anger for some reason and we've got 100 people idling on our IRC channel and we've got over 100 people on our Slack channel asking questions about why did my script break and we've got a really nice community on GitHub where people are submitting pull requests, opening issues, and people are servicing pull requests that aren't the core research team in the Slack lab and it's mind-boggling that people do this for us. And what we've also done is we've also made friends with other open source projects that we use. For example, Z3, Capstone, Unicorn Engine, we've all, I've mostly, made patches to those systems and then submitted them and had them accepted. And for some of these, for Z3, Capstone, we're not quite Capstone yet, Capstone's being finalized, but Unicorn Engine, we manage, I manage, I manage package distribution for some of those things. So we're making friends. We're doing lots of good things out in the open source world. So that's fun. And ultimately all this is possible because we can lift binary code to Vax and execute it symbolically. That's the primary operation down here. We started building Anger. I shouldn't say we, I like taking credit for all these things, but Anger was started before I came into the SecLow around 2013. And when I started building Anger, the question was, well, what analysis IR do we actually want to use? So that's part two of this talk, which is a brief summary of other analysis IRs. First up is BAP, the binary analysis platform, which is an IR that comes out of CMU, Carnegie Mellon University also in the United States, for their research. Most notably, their bug-finding tool called Mayhem is powered by BAP. As a brief side note, CMU was originally using Vax, but they were completely unable to deal with implementing all the clean helpers and dirty helpers, so they just made their own lifter. And it's also important to note that CMU's research is a spin-off company for all Secure, one first place in the CGC. They kicked out asses. Not by much, though. We published an interesting paper looking at the actual gameplay of the CGC and saw the politics. So BAP is pretty cool. It's written in OCaml by people who actually have a background in program analysis. So it's got some cool stuff in it, but on the other hand, it's written in OCaml. And the IR is tied to the larger binary analysis platform that they use. But even further and furthermore, it only supports Intel and ARM. I'm not even sure if it supports ARM64. And furthermore, furthermore, when they started Angular in 2013, BAP was very heavily fragmented and required a copy of their code base in Rotary in order to use. Since then, it has been totally rewritten. So it's a little better now. If you wanted to use it, you wouldn't be totally insane. Next is real, rile. I'm not sure how to pronounce that. It's the reverse-engineering intermediate language. It's someone published a paper in 2009 describing the ideal binary analysis IR, which is ideal. However, it doesn't actually exist. No one really implemented it. So there is an open-real project that is trying to implement this for x86, but if you decide to implement a binary lifter, you will not implement an analysis platform. You will spend three years turning a binary lifter. So back in 2013, we're not using real. So then there's LLVM. This is a pretty serious contender. It's the Clang IR. It is wildly, wildly popular for program analysis. We've started getting program analyst experts coming into our Angerslack and spouting Haskell at us and like, all right, I sort of know what a monad is. Anyway, so LLVM is very robust. It's very established. It's very good. And there's a large community and body of knowledge about how to use it for certain analysis tasks, like various optimization tasks. And symbolic execution with LLVM is 200 times of C++. So that's nice. But on the other hand, it's not really good for our use case. It's designed for compilers, not lifters. There's no real... It's very difficult to reason about register allocation from LLVM. And there doesn't really exist an official lifter from binary code to LLVM. It's all the other way. There's some community projects. MCCMA comes to mind by Trail of Bits that are meant to do that, to lift binary code into LLVM. They sort of work, I guess. Last I heard Trail of Bits has abandoned MCCMA, though don't quote me on that. And it's not... So this isn't really something that we're very interested in using for binary analysis. So then there's TCG, which is the QEMU IR. This is very good. This is what QEMU uses internally to do its optimization and jitting. And one of the really interesting things about being in QEMU is that it suddenly supports everything QEMU supports, which is everything. Everything is supported by QEMU. But then there's... It's designed to be used for QEMU and nothing but QEMU. So the only implementation is just buried in the depths of QEMU that we once burned an entire intern trying to get it out. But... That was weird. But interesting enough, one of our colleagues in the last few months has successfully done this. So there are packages going into QEMU being talked about right around now that have to do with being able to compile QEMU as LibTCG. So once that goes through, we would actually be able to run anger on other things that QEMU supports. Now there is VEX. Does VEX see people in the audience? Does VEX stand for anything? This is very important. This is very embarrassing. It actually stood for Valgrind Experimentals. Valgrind Experimentals. Interesting. It would be better if you didn't know. I'll forget that, don't worry. So good things, very good things about VEX. It's obviously got an official implementation. LibVex, there it is. And it supports tons of architectures. Anything Valgrind supports, that's very good. And it is designed for binary analysis and instrumentation. That's also very good. And it's written in C, so its structures are well-defined and easy to export to other languages. Under active development, it supports a very wide range of ISAs. Like if you look into other analysis platforms, they've got long-running issues open for months and years about, well, we've got to support the SSE extensions to x86. Who wants to write that? Nobody. But VEX has that, that's good. There are some issues with VEX, though. It is designed for the Valgrind use case. So dynamically executing user mode programs is what it caters to. And then, furthermore, there's no real way to get the IR out of LibVex. The LibVex workflow is just this one function, LibVex underscore translate, which does this entire pipeline that Julian had on the screen earlier, of lift instrument optimize code gen. And we only really care about the first part of that. We only really care about the lifting. So for a while, we had this really, really janky solution that commended out half of LibVex translate and then used one of the instrumentation function to copy up the IRSB. I fixed that recently. That's good. Furthermore, you do have to implement a billion IR ops and C calls. And some of them are pretty weird. Like there's IR ops for floating point sign and cosine, et cetera. And furthermore, it's not really SSA. Julian talked about this in the previous talk as well. The IR has no interconnectivity of control flow. There's no ability to reason with just the IR about control flow. And furthermore, from a real SSA IR, you want the memory rights and register rights to also be single static assignments. I'm talking some pretty nasty program analysis stuff, so sorry if this is going over people's heads. But none of these are showstoppers. That's the important thing. Vex is the one that we want to use, and Vex is the one that we ended up using. So, that's what the next part of the talk about. That's what the next part of the talk is about, in words. So, what did we do? We forked Vex. There was our fork of Vex sitting at github.com slash anger slash Vex, and it makes a lot of changes to it. And I'm not going to lie, a big part of giving this talk is me being able to be in the same room as a lot of our ground people, so we can pitch a whole lot of changes we want to upstream to Vex. There's a lot of them. This is the part where things are going to get very, very technical. So, if you're not interested in the specific lines of Vex slash priv slash guest on 2IR.C, this might be a little weird. So, ultimately, so I talked about the issue of the whole gigantic LibVexTranslate function. So, what we did is we split it into two functions, Lyft and CodeGen. There's still the LibVexTranslate function that just calls one and then the other. We've made sure to maintain all the interfaces, so theoretically you can just merge these in the background, we could still totally continue working. I haven't tested this, which means it's broken. But, yeah. So, then there's the problem that LibVex's multi-arch mode doesn't actually work, which is to say that there's this idea of Vex that it can lift from any host and compile to any guest and compile to any host, and this will all magically work, and it really, really, really doesn't. Oh, I've got some good news about you, about some patches we'd like to upstream. And furthermore, there's a lot of assumptions made in various parts of various lifters that the host is the same as the guest. And that's nasty. So, we have patches for that. Furthermore, we'd like to be able to use anger to analyze things that aren't just used in the program. We had a project a few months ago, a few years ago, about analyzing some x86 firmware. So, we have some patches that make it feasible to analyze real mode programs in x86. And then, again, then one of the final things that we want to do is just sort of generally improve the meta-properties of the IR that dynamic execution ignores, but static execution really, really means. Like, for example, making sure that all the jump kinds are always accurate. So, at the end of each vex block, when you translate from one block of vex IR to another block of vex IR, there is a jump kind, which is what kind of jump is it? Is it a boing jump? Is it a function call? Is it a function return? Is it a sys call? What do you want to do? So, that's not really necessary if you're just executing through the code. But once you're performing analysis on it, you need to sort of start keeping track of what function you're in. It's very important that that's right all the time. So, there's a couple of cases where that was wrong, and now it's right. Is it even really knowable? Nothing is ever really knowable. Yep. Seriously. Some of the jump kinds, particularly the spot function, in terms of the impossible, we'd really not love to know that because then we could make code and work on a lot of platforms. But it seems to me impossible to know. Yeah. There's actually currently an issue open on our end about one of our post processors that is overzealous about marking something as a return. So, we need a better heuristic for that. But all the patches that I'm about to present are good as far as we know. They're strictly better. Okay. Let me know if that's true. Yeah. So, let's take a look. I'm going to run that huge bash command and we're going to cycle through all the commits, all 30 of them, and we're going to take a look at what exactly I've done. Uh-uh. Please tell me that's my history. Please. Okay. I guess I can just copy that. I'm glad I kept it around. Hang on. Yeah. Yeah. That's the one. Anyway. So, we use Git, not SVN, because we love ourselves. So, our first commit in our repository is just importing our 3299 SVN. This is, that was the most recent commit as of about a week ago. I re-based everything on top of the current master. So, this should all be good. So, this is just import Vex into Git. So, the next thing we do is just adding a Git into Git. So, I'm going to run that one character and move the terminal that one character to the right. Ah. That's important. Hang on. Good. All right. First off, Tile GX doesn't work in multi-arch mode for some reason. The make file just sitting in the Vex repository seems to have been not updated in a very long time. It doesn't even include the object files for the Tile GX code. Yeah. Yeah. I was looking at those messages and thinking, maybe I shouldn't put in the effort to support this. So, disable Tile GX in multi-arch mode. Second one. In the x86, it's important that we make, we switch these LDT and GDT registers from being h-words to being relongs. The goal is that they take up a consistent amount of space regardless of the host architecture. And this is important because we have a static mapping and anger of all of the offsets in the guest register file. And we'd like to not have to have some magic way of updating that regardless depending on what your analysis platform is. Next, we clean up the build system. This is just a big cleanup of the Vex build system. It is big and it is clean and it paves the way and oh, this is actually an important change I should go over. Where's the GenOffsets program? Right. So, there's this public I'm doing my best. So, there's this program called GenOffsets in the libvex build process which generates this public header pub slash libvex underscore guest underscore offsets dot h. And the idea is to hold on to how there'd be a public record of what the actual offsets into the host file, into the guest register files are. Like what offsets do you need to look into the register file to find EAX or R0 on ARM or R0 on PowerPC? Previously, there was a real hacked up grep into said into something to make everything work. But because of that change that we just made, the one with changing the h-words to the u-longs, now everything is consistent across every platform and we can just we can use something much simpler in order to actually, in order to grab those offsets. In this case, it's just compile a program that includes that just runs the size of macro a billion times and dumps them all out and just dumps them all out into that header file. Does this work even when cross-compiling? Huh? Does this work even when cross-compiling? Yes, that's the idea. Next, support compiling for windows via NSVC. This is this was not fun. It's a lot. It's basically a whole bunch of the real kicker is deaf. We conditioned out a whole bunch of weird vlogs, code with another version of MSVC understands. Okay, and then here's the stuff where we just do a bunch of defines to step out all the GCC specific functionality. I haven't, I got it to work at one point and then my windows machine fell over and died so I'm not really sure how well it works right now, but it worked and it can probably work given about 30 minutes of dead time and a working windows machine. And then there's just a whole bunch of things about, for example, MSVC can't handle empty anonymous structs so just a bunch of random hacks like that. It shouldn't be any overhead, it's just weird stuff. Next is Next is we replace there's this adder type which is this generic host word that sort of switches between 62 and 32 bits based on the architecture. That's no good because then you can't analyze 64 bit from a 32 bit host. Yeah, that's a pollution, it should never go in there. Yeah. So we just, and this is a bit of a hack it should probably be addressed more carefully but for the time being it just needs to be 64 wide. Next we add a next we add a function called libvex update control. There's this vex control struct which is sort of a global variable floating around vex that can add that adds the ability to have just sort of global options for how the optimization process should work and we want you're only allowed to set this once that was the problem you set this in the libvex init function and then you're never allowed to touch it again which is not ideal when you want to update for example the maximum number of instructions that you'd like to lift and later on in this thing I'm going to add a couple more options and it's useful to have them partitioned out like this, so cool. Next, next is the thing I'm talking about we split libvex translate into libvex lift and libvex codegen so it's not a huge deal we just here is it ah it's you can't really see it but there's but libvex translate has just become just these green just these green lines right here which calls libvex lift, libvex codegen which turns out as you're done not super hard. Next is we add a parameter to the vex control that is the maximum number of bytes per lift there is the there's already a concept of maximum number of instructions per lift but we would also like to be able to have a maximum number of bytes per lift useful. Furthermore, there are a lot of weird optimizations that happen in the lifting process which we which are have negative effects on analysis for example in the arm mode on the thumb lifting it tries to do this look back behind the current instructions to see if any of them could have been a conditional instruction and if they're not it means you can optimize the hell out of that code. However there's use cases from Pyvex that doesn't make sense where there doesn't exist code behind the current code where there's not a continuous mapping of just the code segments so we need to be able to disable that behavior. So then so then previously the onlifter's endness endness was dependent on the host which doesn't really make a whole lot of sense so now we're dealing with the guests and furthermore involves just some changes to make sure that you lift the you pull words out of memory with the correct endness etc etc. Next I have no idea why this code ever works but here it is at some point you just take the guest access cast it to a host pointer and try de-referencing it and that makes absolutely no sense so here's a fix Yes This is a lot of relatively small changes Yes Did you want to talk about changing the IRR? That's a much harder problem This is like Yeah There are no real changes to the IRR We like VEX a lot We like the way it is and we don't have any solutions for sort of the architectural problems For example it doesn't give many real representation of what happens in between basic blocks We don't have an answer for that I thought you had this No No I wish I guess I can talk about this in one sort of general patterns that Valgrind doesn't support what we would like to For example there's previously the assertion that when you have a service call on an arm the service call number must be zero and when you're analyzing good firmware that's not always the case There's a lot of small changes Yeah This is really the architecture level stuff that's hard to do The top level structure Yeah I think at this point I've explained all the structural changes I stuck those pretty early in the history If you've been watching the dates they've been jumping back and forth What's something structural that we can talk about MIPS to So can I just say if you actually just jump this law into the standard Valgrind I haven't tried it but it should It really should I took some care to make sure all the interfaces are preserved and any new options that I added are defaulted to the original behavior Let's see Anything else that's interesting Anything interesting Then this is a huge commit that adds support for analyzing x86 real mode code So we add a parameter to the arch info that is the CR0 x86 register and so that controls a big chunk of the new x86 lifting logic and also involves handling the GDT registers correctly and it's just reorganization It's pretty fundamental and needs to drive home the idea that VEX has uses outside of analyzing real mode programs dynamically So optimization and there's a weird type error I found and that's all 30 commits So go back to here That was a lot less than it could have been I spent the last two weeks cleaning up our three years of mess of commit history and packaging into this series of 30 meaningful patches So I've put in a lot of work to make this nice and hopefully just ready to be accepted given some testing So some future ideas that these are some more architectural, some architectural, some structural changes My understanding is that the origin of the C calls in VEX are that they were originally copied from QEMU. I don't know how true this is but the idea that there's some that these, for example when VEX wants to calculate the E flags for an x86 jump instruction like we will so in x86 you can say jump if less than or equal to and what that actually does is it checks just a bit in the condition flags that get set every time you do a math operation and so VEX doesn't want to recalculate those condition flags every single instruction so it saves off the operators and the operand for every math instruction it does all the unnecessary ones get filled up by the optimizer and then when it actually sees that it needs to calculate the bits of the E flags register all these C calls out to this sort of external function which magically knows how to take the operation and the operands and return whether the branch passes or not so and it's totally possible that the existence of these C calls is a hindrance to analysis and optimization and lots of things so it would be nice in the future if we could inline all these C calls and just IR um through them having there be a concept helping there be thread safety in LibVex would be very very very nice because I mean we're in Python so it doesn't make a whole lot of difference but there are many applications for us which are, which live mostly in LibVex for example we do have a blockchain generator that most of its lifetime is spent in LibVex so if we could multi thread that this is hard because Vex is designed to make zero assumptions about its outside model so it has no access to anything that could possibly give it thread local storage so it would probably end up being a callback that it would call but it's just saying hey whoever is invoking me please give me my thread local storage block and it would do that but that would involve moving literally every single global in LibVex into that huge thread local storage struct so it's hard but it would be useful and require a lot of refactoring so multi arch mode works at least now from a little endian host we've tested this pretty extensively from 32 bit and 64 bit little endian hosts you can lift without faults all architectures we haven't tested this with big endian hosts and my feeling is that it's going to fail if you try to lift on a MIPS processor et cetera et cetera et cetera that's not important this is very urgent the indentation in LibVex is three spaces that feels like some sort of joke and one space would be better than three spaces honestly so we need to discuss how to pay the bike share yeah so on a separate note on a less joke filled note licensing is a bit of an issue so LibVex is GPL this is a little scary because we don't want anger to be at GPL our university wants anger it wants all our code to be BSD and we have this belief that we've sufficiently developed ourselves from dependency on LibVex through having multiple backends to Pyvex having no real strict dependency on the exact list of enums that come out of LibVex but in the end it ends up being this weird legal question of what does the GPL cover does the GPL cover the implementation of LibVex or does the GPL cover the concept of the Vex IR we really don't want to find out the answers to that question so the easiest thing that would the easiest thing we think would be for there to be a there's this library license exception runtime library exception that gets added to LibC for example which is GPL but there's no but just because you link with LibC doesn't mean that you're required for your program to also be GPL so that's probably something that needs to be discussed in depth but that's a important issue that's important to the livelihood of anger and me so that's pretty much it that's the anger project that's our interactions with LibVex and that's me being funny on stage for an hour I'm glad to take any questions that you have but is it okay is it mostly because of organizations and my inlining or is it is there anything else more fundamental that stops you from knowing is he said that you need more information he said that you can't leave the analysis and strength so the nightmare case is on arm and thumb there's no such thing as ret instruction there's just this weird instruction which pops a number of things off of the stack and puts them into various registers and this can include the program counter so yeah so it's just but that's like a return yeah so that's the heuristic that he tried to implement and it's not the exact issue that's coming up isn't right but it's an instruction problem it's an instruction problem I think I think there are some CFG problems but like absolutely and I think I'm not the person who deals with CFG that's a very smart person named fish a PhD student in our lab fish named person we have lots of we have a very complicated control flow recovery algorithm it I'm pretty sure there are considerations for the CFG cases in there so everything is perfect everything is unknowable anything else how do you deal with C score deductions memory locations that depends on things you might not know for example yeah so you mentioned memory locations this is a general problem in symbolic execution what do you do when you have a store to a memory address that's symbolic and the answer is we give you a lot of tools to decide what to do you can either concretize the memory storage address you can concretize it to a range of possible addresses in some store conditionally to all of them the less tractable it is that's an open question what's the best way to do it there's lots of publication on what to do it and we try to provide everything you can so you can pick what you need to do with your analysis that's why we call anger a sweet so you can access tools to do that you can access tools to show us something to do longer about that yeah oh wait a minute you mentioned syscalls we're in the middle of refactoring the precise relationship between a program running in anger in its environment but the idea is that oh boy so I mentioned that SimiVex can do things other than just execute Vex well one of them is execute a syscall the main top level loop is well if we see that the previous jump kind is IJK sys instead of running Vex we run the syscall engine then the next time we see that we're all trying to execute more Vex it depends on the actual attacks you're running your your relation basically how do you how do you because it's static and it's static analysis so if you have files in parallel something that does not exist at the analyze time so you're talking about for example what does the open file syscall do yeah for us it just creates the idea that well there's two cases either the open succeeded and it didn't if it didn't succeed you can create a successor state with a failure state at that state and if it did succeed you create a concept of an open file with unknown contents symbolic contents so that any so return a file descriptor and then any time you read off that file descriptor it will return symbolic data and also the possibility of the OF basically you're also embracing this it's big this is a project we've been doing basically nonstop for the last three years it's big about your SMT calling how do you handle 40 point numbers Z3 has primitive support for loading point numbers it does work it's very very buggy we've found numerous seg faults in C3 unable to track down to a root cause so sometimes what we do is I think the approach that we took during the CGC for maximum resiliency was every time we see a floating point operation we just say throw up our hands nothing we can do concretize any symbolic values that turn into floating point and then every time we see an actual operation we just turn them into python floats add them put them back into bit vectors so then this maintains tractability and usually when there's bugs they don't often come from floating point nonsense if we wanted to really if Z3 works then we could just put everything through Z3's symbolic IEEE 754 I work with Z3 as well and recently I found this so it's much better there's an interesting amount of research out there about for frameworks like this which just want a solution to something what you can just do is you can spin up any numbers of SAT solvers in parallel and just use the one of whichever one returns first use the result so that's an approach that we've wanted to implement for a while using which one did he say was good? matzat okay thank you very much anything else? that will be all