We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

REpsych: psychological warfare in reverse engineering

00:00

Formal Metadata

Title
REpsych: psychological warfare in reverse engineering
Title of Series
Number of Parts
109
Author
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Your precious 0-day? That meticulously crafted exploit? The perfect foothold? At some point, they'll be captured, dissected, and put on display. Reverse engineers. When they begin snooping through your hard work, it pays to have planned out your defense ahead of time. You can take the traditional defensive route - encryption, obfuscation, anti-debugging - or you can go on the offense, and attack the heart and soul of anyone who dare look at your perfect code. With some carefully crafted assembly, we'll show how to break down a reverse engineer by sending them misleading, intimidating, and demoralizing messages through the control flow graphs of their favorite RE tools - turning their beloved IDA (Hopper, BinNavi, Radare, etc) into unwitting weapons for devastating psychological warfare in reverse engineering. SOeaker bio: Chris is an embedded systems engineer and cyber security researcher, focused on innovative approaches to low level hardware and software RE and exploitation. Twitter: @xoreaxeaxeax
32
Thumbnail
45:07
Reverse engineeringTuring testOrder (biology)Computer programmingParameter (computer programming)Computer fileReverse engineeringMultiplication signLoop (music)Right angleUniform resource locatorGoodness of fitCompilerSemiconductor memory2 (number)MereologyData transmissionAreaCodeSoftwareSingle-precision floating-point formatSet (mathematics)Formal languageException handlingPrime numberSource codePairwise comparisonVideo gameWordHydraulic jumpEncryptionSystem callFunctional (mathematics)Complete metric spaceVariable (mathematics)Queue (abstract data type)
Data transmissionPrime numberCompilerMereologyReverse engineeringWeb pageScripting language
AlgorithmCompilerReverse engineeringOpen sourceEncryptionScripting languageImplementationNeuroinformatikGame theoryQuicksortVideo game
Video gameComputer programmingPoint (geometry)CalculationMathematicsReverse engineeringEmulatorWeb pageMatrix (mathematics)CompilerTrigonometric functionsPerspective (visual)DarstellungsmatrixComputer animation
Message passingComputer programmingData transmissionReverse engineeringString (computer science)CodeBinary codeMessage passingMoment (mathematics)Perspective (visual)Goodness of fitComputer animation
Message passingInverse elementTransformation (genetics)Revision controlMessage passingShape (magazine)Computer programmingReverse engineeringVisualization (computer graphics)CodeDistribution (mathematics)1 (number)CurveInverter (logic gate)Type theoryEntropie <Informationstheorie>Computer animation
Graph (mathematics)Reverse engineeringMessage passingSound effectStandard deviationCodeArithmetic meanFluid staticsComputer programmingControl flow graphDataflowControl flowGraph (mathematics)Computer animation
Level (video gaming)Computer programmingCodeDeterminant2 (number)Control flow graphBlock (periodic table)Arrow of timeBranch (computer science)Reverse engineeringLoop (music)Statement (computer science)Graph (mathematics)Computer animation
Control flowFluid staticsMultiplication signControl flow graphReverse engineeringAlgorithmAssembly languageQuicksortPresentation of a groupBitPoint (geometry)Graph (mathematics)Computer animation
Reverse engineeringControl flow graphMedical imagingControl flowLine (geometry)Hydraulic jumpUniform resource locatorMessage passingComputer programmingCodeOrder (biology)Right angleStatement (computer science)BitGraph (mathematics)Vertex (graph theory)WordComputer animation
Greatest elementControl flow graphLine (geometry)Control flowGreatest elementHydraulic jumpKnotSquare numberUniform resource locatorSlide rule
Greatest elementBitControl flow graphSquare numberHydraulic jumpGreatest elementLine (geometry)Row (database)Block (periodic table)
RippingGreatest elementLine (geometry)Set (mathematics)BitRight angleSquare numberGame controllerQuicksortRow (database)Graph (mathematics)Order (biology)Control flowControl flow graphComputer animation
Asynchronous Transfer ModeUniform resource locatorBranch (computer science)Matrix (mathematics)File formatQuicksortComputer animation
Macro (computer science)Control flow graphBlock (periodic table)Hydraulic jumpBitData structureView (database)CodePower (physics)Matrix (mathematics)Macro (computer science)Preprocessor
Asynchronous Transfer ModePattern languageControl flow graphPerfect groupRhombusGraph (mathematics)PixelBitBuildingUniform resource locatorComputer animation
Right anglePixelUniform resource locatorShape (magazine)Control flow graphDifferent (Kate Ryan album)BitPattern languagePreprocessorComputer animation
Macro (computer science)Clique-widthPreprocessorReverse engineeringData structureMessage passingLine (geometry)Medical imagingRight angleHydraulic jump
Square numberRight angleBranch (computer science)RectangleBitDifferent (Kate Ryan album)Entire functionForm (programming)Control flowGraph (mathematics)Assembly languageOrder (biology)Medical imagingMathematical optimization
RippingGraph (mathematics)Similarity (geometry)CodeSound effectBranch (computer science)Operator (mathematics)Order (biology)Computer animation
Control flow graphSound effectPixelFunctional (mathematics)Hydraulic jumpComputer programmingAdditionSkeleton (computer programming)InformationContrast (vision)Control flowComputer animation
Contrast (vision)Slide ruleClique-widthFunction (mathematics)Point (geometry)Asynchronous Transfer ModeOrder (biology)Line (geometry)Medical imagingPairwise comparisonSinc functionDisk read-and-write headComputer architectureVector spaceSingle-precision floating-point formatBranch (computer science)PixelComputer animation
Contrast (vision)Multiplication signHydraulic jumpComputer animation
CircleRow (database)PixelMedical imagingComputer programmingCodeRaster graphicsOrder (biology)Logical constantMultiplication signPreprocessorDirection (geometry)Data conversionComputer animation
Raster graphicsControl flowProcess (computing)Greatest elementControl flow graphLine (geometry)BitStatement (computer science)Graph (mathematics)
Greatest elementForm (programming)WordElectric generatorControl flow graphChainMedical imagingReverse engineeringCartesian coordinate systemControl flow
InformationDirection (geometry)Control flow graphPreprocessorComputer programmingFunctional (mathematics)Assembly languageMedical imagingRaster graphics
Reverse engineeringComputer-assisted translationFigurate numberVolumenvisualisierungComputer programmingControl flow graphMedical imagingComputer animation
Medical imagingProcess (computing)Multiplication signGroup actionControl flowGoodness of fitRight angleTrail
Demo (music)TrailComputer clusterMedical imagingReverse engineeringCodeMultiplication signComputer animation
CodeMessage passingReverse engineeringComputer programmingControl flow graphControl flowOrder (biology)Computer animation
Order (biology)Task (computing)Right angleEntire functionLogical constantMessage passingControl flowControl flow graphComputer animation
Reverse engineeringComputer programmingComputer animation
Point (geometry)Medical imagingQuicksortComputer animation
VolumenvisualisierungMedical imagingCybersexInformation securityBitDifferent (Kate Ryan album)Assembly language
CodeGroup actionMalwareComputer animationSource code
Real numberQR codeType theorySlide ruleVideo projectorComputer animation
QR codeBookmark (World Wide Web)Computer animation
MalwareMedical imagingCodeMultiplication signHard disk driveComputer programmingBitComputer animation
MalwareDigital photographyCoefficient of determinationComputer animation
Process (computing)BitControl flow graphMathematical analysisDynamical systemPoint (geometry)Reverse engineeringDebuggerComputer programmingSoftwareMalwareControl flowComputer animation
VacuumComputer programmingMalwareCoefficient of determinationMultiplication signComputer animationSource code
Trigonometric functionsIRIS-TComputer iconMalwarePreprocessorCodeSingle-precision floating-point formatProof theoryOrder (biology)CoprocessorTotal S.A.CompilerProjective planeDemo (music)Line (geometry)Multiplication signCartesian coordinate systemFeedbackVulnerability (computing)Reverse engineeringControl flow graphChainTwitterArithmetic progressionInformationOpen setSource codeComputer animation
Trigonometric functions
Transcript: English(auto-generated)
All right, good morning, everyone. Thanks for being here. My name is Christopher Domas. I work for this R&D company called the Battelle Memorial Institute. It's a pretty neat place to work. It gives me a chance to look at a lot of the fringe areas of cybersecurity, which keeps things entertaining. But important disclaimer before I begin, everything I'm going to show is just my own work and my own opinions. Second important disclaimer, everything
I'm going to show serves absolutely no purpose whatsoever. So if you're really interested in a practical talk, this is probably not the right place to be, but I think it's still going to be really entertaining and hopefully see some interesting stuff. So what I really want to talk to you about today is reverse engineering, because I do a lot of reverse engineering. I take software apart and figure out basically
how it works. But for whatever reason, I also spend a tremendous amount of time trying to think about how I can make my life more difficult. In other words, how can I make it harder to take software apart and figure out how it works? So there's a couple of basic ways people normally approach that problem of making things more difficult to reverse
engineer, to take apart. Encryption is a pretty common one to make things harder to understand. Obfuscation of code is another technique people use to make things harder to understand. And then to debugging tricks are yet another tool that people commonly use for anti-reverse engineering, again, to make things harder to understand. There's kind of a theme in all the approaches people normally take for
anti-reverse engineering. You're just trying to make things more difficult to decipher. So I was tinkering around with that over the last few months. And I kind of came up with this neat way that incorporates all of those things at once as a anti-reverse engineering technique. And the idea behind this whole thing is that for the most part in reverse
engineering, we're going to look at the individual pieces inside of a program in order to try to understand what that program's doing. So using a tool like objdump here, we can look at the individual instructions inside of some unknown file and we can figure out exactly how that file is going to work. We can take it apart and figure out what it's doing. So if I ran objdump on some file, I might get
something like this. So an experienced reverse engineer could tell exactly what this was doing in a couple of seconds. Even somebody with no reverse engineering background can actually pick this apart and tell what it's doing with almost no time at all. So starting out, just looking mostly at the mnemonics that are going on here, it's moving zero into memory. That's going to be initializing a local variable. It's pushing something out of the stack as an
argument and then it's calling a function to print that argument out. It removes that thing from the stack and it adds one to its local variable. It then compares the local variable to 100 and if that is less than or equal to 100, it jumps back to the beginning here. So basically it's just going to sit in a loop 100 times printing something out. In no time at all, really just by looking at the instructions
being used, we can understand exactly what this program was trying to do. But a few months ago, I was reading this paper that I found really, really interesting. It was just called move is turning complete by a guy named Stephen Dolan. So really, really simple concept. If you're not familiar with the move instruction, it's a common instruction, basically the simplest instruction in all of
x86. It just moves data from one location to another. Nothing more involved in it. So what about that turning complete part? Well that means that any code that we write in any language could really just be written as a set of these unconditional data transfers instead and absolutely nothing else. And when you think about everything you do in
a program that's actually kind of mind boggling, it's hard to believe. When you think that we're doing arithmetic and comparisons and jumps and function calls and exception handling in our program, theoretically all we need to implement all of that stuff is just a bunch of move instructions. And as I thought about that more and more, I
thought that would be really, really hard to reverse engineer, wouldn't it? Because we would go from something like this where we've got all these instructions that perfectly tell us what's going on inside of the program where we can instantly understand what this program is doing to just a whole bunch of unconditional data transfers instead. So all of a sudden, all the queues we use for reverse engineering have just been removed from the program. We've got nothing to
go off of anymore. Every instruction looks exactly like every other instruction. It is really, really hard to reverse engineer this kind of thing. So I took that idea and I've been running with it over the last few months and at the beginning of DEFCON on Thursday, I released a move only C compiler that will take C source code and
translate it into only move instructions. So this is pretty fun and as far as I know, this is the first single instruction C compiler ever, mostly because I don't think anybody's ever wanted to create such a thing before. But it turns out to be kind of neat. So I call this thing the mafiscator because it turns programs into moves as an
obfuscation technique and we can really do anything with this. So for example, I've got this really simple little C program that prints out prime numbers, so not much involved there and I can compile this with a traditional compiler like GCC and look at the instructions it gives me and that's great. But if I look at these instructions, it takes
almost no time at all for an experienced reverse engineer to pick this thing apart and understand exactly how it's working. But on the other hand, if we use the mafiscator, the mafcc compiler and do the exact same thing, all of a sudden we've got nothing but thousands and thousands of unconditional move instructions implementing this thing. But
the cool part is if we run this, it just calculated 10,000 prime numbers using nothing but unconditional data transfers. But that is a nightmare to try to reverse engineer that kind of thing. But it's not limited to simple little examples like this. If you go onto that GitHub page, it'll include this little check script. So what the check script is going to do is it's going to automatically
download an open source AES implementation in C. It's going to run that through the move compiler. As soon as it's finished compiling the thing, it's going to dump out the move instructions associated with that. And you'll see that with just a couple million move instructions, you can implement AES. So this is not fun to work with as a reverse engineer. But it's really, really neat to think about
that just by moving data from one place to another, we can do really, really complex computations. So I sort of meant this as like a thought experiment in anti-reverse engineering, but mostly I just thought it was funny that you could have move instructions doing really, really complicated things. So it finally finished running that and it'll actually run our AES algorithm and encrypt and
decrypt some data using only move instructions. But we can make it more complicated. I wrote a little nibbles game if we link that. So we can play video games now with only move instructions. We can take it a step further. The move
compiler we created actually contains a complete move only floating point emulator. So you can do floating point math with only move instructions. So since I could do that, I decided, well, what's the best demonstration of floating point math I could come up with? I figured I could make a 3D engine, which is a lot of floating point math like trigonometric functions and matrix transforms. And then I
could compile that with the MOPiscator. So we've got a complete little 3D program here written with only move instructions. We can now do incredibly complicated 3D calculations. I even took this as far as I could possibly
conceive. I actually MOPiscated the MOPiscator. So I've got a program written in only move instructions that compiles other programs into only move instructions. So that's a couple, so this is a couple million lines. We're not
going to sit around waiting for that to finish dumping. So I thought this was a really cool technique. If you actually like reverse engineering, you can check out some crack me's on that GitHub page and see move only reverse engineering for yourself. But after I finished this, I started giving this some serious thought from a reverse engineering
perspective. I thought, how would an experienced reverse engineer approach reverse engineering something like this? What would I do if I looked at a program and I opened it up and all I saw were hundreds of thousands of unconditional data transfers? Well, realistically, I'd go find something else to do. I reverse engineered because I think
it's fun and this does not look like fun to me. But I had a big realization at that moment. From an anti reverse engineering perspective, code doesn't really have to be hard to reverse engineer. All we really need to succeed in anti reverse engineering is none of the things we've
traditionally been using. We don't need encryption, we don't need obfuscation or anti debugging. All we really need at the end of the day is we need to make the reverse engineer give up. That's not necessarily the same as making code hard to reverse. So I started thinking, how else could we make a reverser quit? If we don't want them to reverse engineer our code, how could we stop them from looking at it in the first place? And I thought the obvious solution was
psychological warfare. We could demoralize the reverse engineer and try to break down their spirit until they had no more will to continue reverse engineering our code. So I started thinking, how could we actually accomplish that though? It seemed clear that if we wanted to somehow
demoralize the reverse engineer, we needed some way to influence them. We needed a way to influence the reverse engineer through our code. All they're going to get is some compiled binary and I need some way to have that binary then influence the person looking at it to try to get them to stop looking at it. So it seemed clear to me if I wanted my binary to influence a reverse engineer, I
needed some way to send them messages through that compiled code. So there's some easy ways we could try to send a reverse engineer messages. We could just embed a string in our program like stop looking at my code. The reverse engineer when they're dissecting our program will probably eventually see that string but that's not a very good technique. I'm
a reverse engineer. If I saw somebody put a string in their binary saying stop reverse engineering me, I'd probably laugh at that. That's just silly. That's not going to be effective. So string's not a really good solution. Then I thought entropy. A lot of modern programs are starting to look at entropy distributions as a reliable way of some types of reverse engineering. So like if you download the
latest version of Hopper, the reverse engineering tool for the Mac, they actually have entropy visualizations through Hilbert curves inside of Hopper. So I thought maybe if I ran my message through an inverse Hilbert transform and adjusted the entropy inside of my program, I could then send the reverse engineer messages through the entropy distribution of my program. So it works. You can do this.
But again, not the most effective technique. Somebody's going to see this and then just move on to reverse engineering your code. So still not going to really accomplish what we want. All these are horrible solutions for sending a message to a reverse engineer. At the
end of the day, no one's going to see the message. If they do, they just won't care. They're going to move on, keep reverse engineering. So we need something better if we really want to be able to send a message to reverse engineers. So I started thinking about the tools that I use for reverse engineering. So if you're not familiar, this is IDA Pro. This is probably the most effective standard in static reverse engineering. Any professional reverse engineer is going to be using IDA Pro to
dissect your code. So I really wanted to focus on IDA as a means for sending messages to reverse engineers. And IDA can do some basic things for us. Like it can show us the code inside of a program just like we were doing with Avstump before. But IDA has a more powerful capability and that's control flow graphs. So the idea behind control flow graphs is something like this. We've got these basic
blocks that do simple things and then at the end of a basic block, the program makes some kind of determination and it's going to go down one path if it decided that thing was true or a different path if it decided that thing was false. So we've got a whole bunch of these basic blocks that are all connected by decisions inside of the program. The nice thing about these control flow graphs is in
just a couple of seconds I can tell at a high level exactly what this program is going to be doing. So for example, this branch here is going to be an if statement. This arrow going back here, that's a loop happening inside of the code. So at the end of the day, most reverse engineering is going to be done at this level, looking at control flow graphs to quickly get an idea of what's inside of assembly. So almost every major, at least static reverse engineering tool
is going to have control flow graphs support and anybody doing static reverse engineering is going to spend a lot of time looking at this. So the Hopper reverse engineering tool for Mac has control flow graphs. BinNabi control flow graphs. Rodare has control flow graphs. This is the thing to use for reverse engineering. So for this presentation we're going to look at IDA a little bit but
the algorithm itself will work on pretty much any of these tools that you look at. So the idea behind this was sort of spawned from a lot of late nights of reverse engineering. So when it's 3 a.m. and you're looking at assembly code and control flow graphs and you haven't slept for 30 hours because you're just staring at this thing, you're not entirely with it at some point. So if
you stare at these control flow graphs long enough, what I found is eventually they start to look like things. So this is a very, very simple control flow graph in IDA but a lot of professional reverse engineers are dealing with very, very complicated control flow graphs in IDA. When you're dozing off at 3 a.m. once in a while you'll start to
see things inside of these images. So I felt like this was a Tyrannosaurus Rex at 4 in the morning. But that gave me an idea. Maybe we could send the reverse engineer a message through control flow graphs because that's something they can't look away from. That's exactly what they're looking at in our program. So if we could
send them a message through the control flow graph, they've got to stare at our message which is exactly what we want. So maybe we could draw pictures with the control flow graph. Maybe we could send them texts through the control flow graphs of our program. But in order to do that we need to understand exactly how our reverse engineering tools are rendering these control flow graphs. In other words, we kind of need to be able to reverse engineer IDA to figure
out how it works. So it's a little bit of a daunting prospect to reverse engineer a reverse engineering tool but it actually turns out to be fairly straightforward if you just tinker with it for long enough. So my first idea for how we could draw pictures or send messages through control flow graphs was pretty simple. I stared at enough assembly and control flow graphs to know exactly how to
draw a horizontal line. If you have a switch statement in like C, it'll draw a horizontal line when you're looking at a control flow graph. What I call orphaned jumps will also do that. So let's say you've got a whole bunch of jumps that all jump to exactly one location. It's not really clear how the program got to this jump here because the instruction right before it didn't go to this jump. So
we've got all these jumps that didn't seem to come from anywhere and when you have that situation it turns into basically a horizontal line in the control flow graph. So I can draw horizontal lines using that technique. I can draw vertical lines in a much easier way. Basically any non-branching code in a control flow graph will create vertical lines. So a whole bunch of knobs that don't do
anything creates a nice solid vertical line when looked at in a control flow graph. So I thought well, I've got horizontal lines, I've got vertical lines, I can make an etch a sketch in IDA. So that seemed easy enough. All I wanted to do was start out by drawing a square. So here's how I thought you would draw a square with these
techniques. All we're going to do at the top is have a bunch of jumps that all jump to one location to draw a horizontal line. Then we need that horizontal line to connect to both sides of the square. So on the left we're going to have a jump to the left vertical line and on the right we're going to have a jump to the right vertical line. So left slide is just going to be a whole bunch of knobs that don't do anything to draw that vertical line and then we're going to
tie it to the bottom line with a jump. And on the right side a whole bunch of knobs that don't do anything to create a vertical line and we're going to tie it to the bottom horizontal line. Same thing for the bottom, we're just going to draw a horizontal line. Easy enough. But when we drop this into IDA to look at the control flow graph, we're not quite to a square just yet. We need to make some modifications to this but this tells us a little bit about
how IDA is trying to lay out these control flow graphs. So if we look at this piece here, this tells us a little bit that IDA is actually trying to combine or trying to line up a bunch of our nodes. It's trying to line the blocks in a given row. So we need IDA to not do that if I want that horizontal line to move back to the bottom of the square. So instead of using knobs for my vertical lines, I
decided we could use this jump plus two. All that is is a jump to the instruction immediately following it. What that's going to do is it's going to break those vertical lines up into a whole bunch of little nodes so that when we try to draw this again, IDA aligns our bottom line with the last set of little nodes in our vertical line. So I at least got the bottom line moved to the bottom here. We're getting
a little bit closer to actually being able to etch a sketch inside of IDA. But obviously there's still an issue. I've still got my vertical lines right next to each other. I wanted those to be on opposite ends of the square. So we kind of see that IDA is trying to keep rows and columns together. It's squeezing all of our control graph into as small an area as possible. And it does that in order to minimize the branching distance inside of this thing.
So I spent a couple of hours tinkering with this and really could never find a way to get those vertical lines to separate from each other. So that's sort of the death of my first idea for how we could draw through control flow graphs. But we learned a lot along the way. We learned about how rows and columns are arranged in IDA. Namely
that we have control over how the rows are arranged, but IDA is going to have control over all of those columns. So we need some way to fight back against IDA. If IDA is trying to rearrange our stuff, I need to have some way to stop IDA from changing my stuff around. So my idea was to force IDA to keep all these nodes in place. I could sort of
tie the nodes together as tightly as possible to prevent IDA from trying to rearrange them. So if we look at what a basic node in assembly looks like, it's pretty much always like this. It's a bunch of assembly instructions that do something and then at the end it branches to either one location or another. So I thought what if we had a whole bunch of these nodes and we tied them together like this. Then IDA couldn't really move any one node because it's
going to be trying to pull all the other nodes with it. So this will force IDA to try to keep everything in place for us. So the assembly to accomplish that looks something like this. All we have is a conditional jump at this instruction down to either this place or it's going to fall through to the node below. This one will jump over here or it will fall through to the node below. So we've
got a whole bunch of instructions that are all tightly tied together in this sort of matrix formation. When we look at what that looks like in a control flow graph view, this is what we end up with. It's actually not that bad. We have defined structure that was somewhat close to what we expected to accomplish. So we can touch this up a little bit. First we've got this giant block here that seems to be raising the nodes around it. So we can
cut that giant block in half by adding a jump into the middle of that. So we need some way to create a whole bunch of these. I don't want to create a whole bunch of these by hand. NASM fortunately has some really, really powerful preprocessor macros. So this is just all the code we need to create NASM macros to generate one of these layouts for us. So that lets us create a whole bunch of these
nodes very, very quickly so that we can begin looking at more complex patterns through the control flow graph. But I've got kind of an issue here, right? I want to draw something with this but I've got this lopsided rhombus. It's going to be hard to draw with a lopsided rhombus. What I really wanted was like this perfect grid of assembly
nodes that I could work with. So we just need to change a little bit about the way we're building this graph. What we're ultimately going to be after is a way to draw with these nodes by turning pixels on and off by removing or adding nodes in exactly the right location. So I thought
something like this. If I wanted to have this pixel off I'm just going to remove this node and I could draw that way. So first we're going to try to get this into a non-rhombus shape. We're just going to rearrange our control flow graph by tying the nodes together a little bit differently. We take it with the assembly a little bit. It's a little bit trickier to write things this way and when we drop that into AIDA this is what we end up with.
It looks like a garbled mess that doesn't at all accomplish what we want but if we look really carefully there's four nodes there that are perfectly arranged in a grid pattern. So I can work with that. If we've got four nodes in a grid pattern we can get more nodes in a grid pattern. So back to NASM's preprocessor. We can use a preprocessor to generate a whole bunch of these and this is what we end up with. We're getting almost to a perfectly
well defined structure that we actually have some decent control over and maybe we could start using this then to send some messages to the reverse engineer. We've got a few things to touch up here. First we've got this weird line on top. Again we're going to cut that big node in half by adding an unconditional jump in the middle of that. We've got some nodes escaping from us on the right. I decided I could
push those back into the rest of the image by having a bunch of orphan jumps to each of the nodes on the right. Now we've got another issue. We've got a rectangle here. It's not a square. So all we really need to do to make this into a square is add a whole bunch of jump instructions into each individual node and we'll make this thing a little bit taller. Once again though we've got some nodes trying to
escape from us. This was a little bit difficult to figure out what was going on here. Turns out that NASM, the assembler we're using to do this, uses two different forms of jump instructions depending on how far you have to jump. These nodes down here had to jump a little bit further than the rest of these nodes up here which essentially made them wider than the other nodes inside of item. All we have to do is
turn off optimizations in NASM in order to use the same jump instruction for every node and we finally have a perfect grid that we can actually start trying to draw on. So we're finally ready to implement our idea. Maybe we can start drawing on this by turning these nodes on and off by simply removing a node. So I tried to remove a single node from this and the entire thing breaks. IDA tries to
squeeze all the nodes around that thing together so we can't really get a nice image by trying to delete nodes from this graph. So that was the death of a very long idea too. But maybe we can resurrect it. I didn't take you this far for nothing. We can still, well we can't remove a node from
this but maybe we could do something similar. Maybe we could leave all the nodes in place and then fill a node with code if we want it to be on or leave it empty if we wanted it to be off. So something like this. The nodes that I actually want to look like they're on are going to have a bunch of no ops inside of them. And the nodes that are off aren't deleted. They still exist and they're still tied to the
nodes around them with a jump instruction. But they don't have any dummy code inside of them in order to fill up that node. So now when we try that we almost get the effect we want. We can see this looks like a pixel that's been turned off inside of our control flow graph. So with that we can extend the idea and begin actually drawing some things
inside of the control flow graph. So this was the first thing I ever drew was a circle inside of this program's control flow graph. There are a few things I wanted to touch up here. I decided to get rid of this giant node at top. That's actually caused because this is the first function in the program and IDA is adding a whole bunch of additional information to that node. So we just make this thing not the first function. We get rid of that. We've got these funny
little orphan jumps on top. We'll just add some dummy code to get rid of those. I really wanted to enhance the contrast in this. If I go back a slide you'll notice that these look white but these still look kind of white. These nodes that are supposed to be off. So how do we enhance the contrast for the image that we're trying to draw? Well the idea is that an empty pixel here still used two lines. It had that jump instruction and a label. All we really want to
do to enhance contrast is reduce the impact of those two lines and you can reduce the impact of those two lines by increasing the height of the overall node. That way those two lines won't matter that much in comparison to everything else. But in order to increase the height of the node we need to also increase the width of the node since they're supposed to be square. So in order to increase
the width of the node what we need is a really really long assembly instruction in order to make that node take up as wide a space as possible. So there might be longer assembly instructions in x86 but this was the longest one I could think of off the top of my head. That's vector fused multiply alternating add and subtract from packed single precision floating point data using the XMM registers with a CS override and a very complex
addressing mode. So this is a weird architecture that lets you do insanely long instructions like that which is really convenient because it let me get the enhanced contrast that I was after making each node really really wide. So we've introduced a new issue. We've still got
nodes trying to escape again. So every time these nodes try to escape we've got to push them back in place. And the reason these nodes are trying to escape because we made this node really really wide. But now the jumps that I was using to push all those nodes over to the left, those nodes are really really small compared to these really really wide nodes. All we have to do to fix that is add one of those really really wide
instructions to those jumps that push everything in place. So after we do that we've got this nice perfect grid with a circle drawn in the middle. So we're getting there there's a few more things to tweak along the way. There's an issue where if we had all the pixels in a row turned off the entire image would collapse on itself. So we keep the column on the far left always on to prevent the image
from collapsing. I didn't like the idea of having knops filling up these nodes because knops are very clearly not code. So I added a junk code generator that would add some dummy instructions that don't really do anything but they also don't fault the program so they can actually run. Finally I didn't want to have to draw this thing by hand every time. I had to draw that stupid circle by hand. So I created a bitmap to NASM preprocessor assigned
directive converter so that we could actually take bitmap images and convert those into NASM constants. That lets us take a bitmap image convert it into these pixel values that we can feed to NASM in order to generate the code for us. So finally we can take a bitmap image like a smiley face run it through this entire process and create a control flow
graph for the smiley face. So we're getting a little bit further. There's still some things I didn't really like about this. I'm a little anal-retentive. I didn't like the fact that there's a blue line on the bottom but not a blue line on the top. So I fixed that by opening the
whole thing with a switch statement that was going to tie all the top nodes together. Once I did that I figured out that all the work I really went through to tie all these things carefully together wasn't really necessary. As long as you tie the top and bottom together like that, you don't need to tie the individual nodes together quite so tightly. They'll stay in place as long as the top and bottom are in place. In other words, whereas before we
had this node tied to this node and this node, we no longer need that. We can just have this node fall directly into the node right below it. So that forms what I call the Resyc toolchain, reverse engineering psychological warfare toolchain. I'll show you exactly how we can use this for some interesting applications coming up. But what this does is it gives us a way to generate assembly
instructions such that they form images in their control flow graphs. So collectively, if I go into my Resyc source, what I've got here is a bitmap image that I want to render. It's really, really small, but it's just a skull.
And that's what I want to turn into assembly instructions to manipulate the control flow graph of my program. So what we're going to do is run make to turn that image into some assembly code. And all it's going to do is turn that image into a bunch of preprocessor directives. So
now that we've got that as preprocessor directives, we're going to go ahead and make an executable whose control flow graph will mimic that image. So we run make, run it through this whole thing and it will generate some functioning executables. You can make these executables do whatever you want for these purposes. I decided to make them render
Pusheen the cat. So they actually run. They're not fake executables. They run. But if a reverse engineer wanted to approach this and figure out exactly what this program did, they're going to have to go over to their trusty tool IDA and
pull in this executable and examine the control flow graph. So when they do that, they then see the image that we just created. What an optimum time for a tiny break in the
action. How is he doing? I think you all know about our
little tradition new speaker. Welcome to all the new attendees at DEF CON this year. Here's to you. Good job. Thanks, guys. Give me a second until I get back on track
now. So I was trying to think of where else we could take this thing. What could we actually do with these images? We're trying to let the reverse engineer know what
we think of their work. So we can let them know that maybe our code doesn't even do anything useful. You know, maybe this whole time we're just trolling them. Or we can let them know what we really think about them poking around in
the code that we work really, really hard to create. I don't like people poking around in the code that I worked hard to create. But ultimately, the goal wasn't just to send them amusing pictures. It was psychological warfare. We wanted them to stop reverse engineering our code. But I
think this opens up a neat opportunity. Namely, as a reverse engineer, I have to sit and look at those control flow graphs. The reverser is forced to sit and stare at whatever message you embed inside of this program. So you can use this to your advantage. Crush their soul. Basically make them abandon hope and not want to reverse engineer your
code anymore. So what else could we put in here in order to accomplish that task? Well, we could let them know that the entire situation is futile, right? Just remind them constantly. This isn't going to turn out in your favor. We
could remind them that if we're good enough to send them messages in our control flow graphs, they're never going to successfully reverse engineer our program. So they might as well just give up now. Or we could just really
go all out. I think this one's over the top. And just remind them that they're really no good at life in general and should quit altogether. I was having fun
with this. I didn't want to just call it quits at this point. I kind of realized that we're not limited to black and white images here. The way we have it, we sort of got these nodes either on or off. But we could sort of make
them gray or not gray by adding more or fewer instructions to this thing. So I took that opportunity to add grayscale support to this so that we could actually render grayscale images. Of course, that opened up a really important opportunity in cyber security history. I decided to
take the first, as far as I know, assembly selfie. That is
from back when I had hair, so I look a little bit different. But it is completely functioning assembly code. So what I really like about the group I work in is I can take something stupid that I made like this and show it to everyone and they'll have 100 good ideas for how to actually use this. So one of my coworkers suggested, well, you
should have a piece of malware and call it the interview. And when you drop it into IDA, you'll find out where your malware came from. It was North Korea. Or another
coworker recommended the ultimate CTF problem, which you could spend hundreds of hours reversing, but all you really needed to do was zoom out and figure out that they were
just sending you on the wrong path. So some of the projectors work here. That's a real QR code. It will really take you somewhere, but you can check that out later on the slides if you have a chance. But that's one type of CTF
problem. But I felt like if this were the DEF CON CTF, they probably wouldn't embed a QR code inside of this thing. No DEF CON CTF seems to be complete without GOAT-C. So for DEF CON CTF, I felt like it would be GOAT-C, but I wasn't
really going to show you guys GOAT-C. So you're welcome. But my favorite of all, a friend of mine proposed what could be the creepiest malware of all time. What if we had a piece of malware that would actually scan your hard disk,
retrieve your personal images, and then rewrite its code based on the images it was collecting. So this took quite a bit of modifications. It was fairly different from what I originally wrote, but I threw together this little C program that would do exactly that. So if we go ahead and run this
little piece of malware, it doesn't seem to do anything. It just sits there, nothing important. But I do have some vacation pictures on here. These are stock photos. Those are not my feet. And this is not my dog. But if I were curious about what this malware were doing, I would toss this into IDA. Get rid of that folder I accidentally
created. So first in IDA, after IDA processes it, it's really not anything interesting. There's nothing in the control
flow graph at first. So I'd analyze this a little bit as a reverse engineer. I wouldn't see anything interesting. At some point I'm going to have to do dynamic analysis. I'm going to have to actually run this thing and see what it's doing. So I'm going to change my debugger here and I'm going to go ahead and run this program. So the program begins to run, but the
first thing it does is it triggers a software break point. It does that because it wants the reverse engineering tool to stop. It wants you to see what it's actually doing. So I'm going to follow this in my reverse engineering tool and pull out the control flow graph so I can figure out what this malware is doing. We zoom out a little bit here. IDA doesn't
like doing this so much when the program is actually running. But it just, huh, those were my feet. And if I keep running this, maybe it's just a fluke. No, the malware is going to stop me again. It's got something new. What's it
this time? That's my dog. Why is my dog in the malware? I'm
always a little worried to get this demo because I hope it's going to find those two pictures but I never know what it's really going to go out and collect. But as a reverse engineer, when malware starts rewriting itself based on my personal information, that's probably when I'm going to call it quits. So I feel like this would successfully implement
what we were originally after. Other ways of getting the reverse engineer to stop looking at our code. So there might be other ways to accomplish that. I think it's neat to keep your mind open and realize it's not just about making things harder to reverse. But overall, this was a really, really fun thing to just tinker with. It was a
grand total of 14 lines of assembly in order to accomplish this and 328 lines of preprocessor macros. But not too shabby. And if you're interested in this, it's on my github at github.com or EAX. That is the Recite Toolchain is what I call that. I would love to get feedback and ideas
on other applications for this. Maybe it's just a fun toy or maybe there's actually something useful we can do with this. If you're interested in the Mothiscator thing, that's the single instruction C compiler that's also on github as of Thursday morning. If you caught me at Black Hat, I released an architectural vulnerability built into the x86 processor itself. Some proof of concept code for
that's also on github. But I'd love to discuss this more with anybody who has some interesting ideas for what we can do through control flow graphs. I might keep tinkering with this over the upcoming week. So if you're interested in tracking progress, you can follow me on twitter. That's xor-eax-eax-eax or same thing at gmail.com if you want
to discuss further. Thanks for your time everyone. This was a fun project. I really appreciate everyone turning up for it. So if anyone has questions, you can talk to me.