DEF CON 25 - XlogicX - Assembly Language is Too High Level

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so yeah those of the people that know me know that I'm always talking about how everything's too high level like DEFCON 20 - I was talking about how a lot of security tools work - high level and how to screw at the analyst that way then there's also recently I got this year if anybody picked this up I wrote about in the good book about how escapees to high-level and then now I'm going to be talking about how assembly language in certain situations can be to high level and just a note in the speaker room back there there's minor disasters so I'm a Cali image broke but whatever I'm gonna roll past that I got screenshots so it's no big deal but um first before I began simple shouts to start with most importantly the person that helped me with all the art you're gonna see in here Kurt cocaine my fiancee she's back there right now not wearing the hamburger earmuffs but it which is funny side note I know my handle is kind of straight edge and it's kind of ironic that hers has the name cocaine in it but I'm also a fat cat fablabs it's a hackerspace that I hack out of in the West Village NYC 2600 also DC 201 because Def Con currently we don't have my C chapter so if we go over to Jersey for that so anyway about me in the context of this slide not about me in general but as a teenager in the 90s on windows 31 I wanted to learn to program but I wasn't exposed to any kind of programming languages I'd I didn't know about BBS numbers to even dial I was like in a little silo but I kind of had the idea that programs still had to be editable in some kind of language in some kind of editor so I opened up notepad and you know naively dragged calc into notepad to see if I can edit this program and what I saw was kind of discouraging I'm like I don't know this language whatever this is this garbage but I want to so eventually as a side note I I did start programming in machine code directly and at Cactus Con last year I did live demo programming HelloWorld in Windows 3-1 stock using debug but back to my journey of assembly language I when I first tried to learn assembly language I tried on that TI 82 just because I thought it'd be simple the z80 chip and I followed a tutorial to clear the screen and that worked out great and then when I try to adventure on my own to clear the memory so I gave up on that and then I went when I was in college I learned officially more academically on Motorola chipped m-68 HTC eleven and that's when I really learned assembly and really fell in love with it and really learned the relationship between machine code and assembly language because one of the first challenges I gave myself was to write a you know self-modifying or kind of like a virus but not really just a program that wrote itself back into memory and executed itself and to do that you'd have to understand the machine code side of it not just the assembly side of it and then lost he used to come to our Phoenix 2600 meetings when I used to live in Phoenix and he's the one that got me into all things parallax he gave me my first basic stamp and he coerced me into using the the propeller chip and I learned assembly on it and wrote some audio stuff and I've also learned the machine code for this as well and the relationship is fairly one-to-one and then down the road my previous employer voluntold me to do Graham training the Graham certification through sans so this is what I actually formally learned x86 ironically it's the last architecture that I've learned not the first one and this screenshot is all the the manuals for Intel for x86 I've actually read them all cover to cover except for volume 4 which I guess is a new thing now so to get into this a little bit I want to start with my feelings of assembly language and machine code in x86 and its relationship to each other so I introduced you to my mental image of the InfoSec bro somebody that bro splaine's oversimplifies things so here's here's like a scenario that you know it's like I'm witnessing this this is kind of a quote of the type of things that you'd hear from a bro splinter about assembly language seeing it's a one-to-one mapping they're basically the same thing you can take machine code and you know exactly what assembly it is it's just it's just once in zero you know he's saying there's no other layers of abstraction between assembly and the processor that's okay the downside is I took all these I didn't make these quotes up I took them out of this book and I'm sorry I know a lot of the authors are Def Con attendees I honestly think that uh I I know but I don't blame the authors actually and even even one of the authors blames the publisher this is an Amazon review the one that shows at the top for this book it's from one of the authors of the book and at the very end he said well I can't help me to try to zoom here that's the thing he says so this talk is about how assembly language and machine code is not one-to-one and I'm gonna go into this and gruesome detail so here's the disappointing part I had an awesome little example in Cali it it was just a toy vulnerable program toy exploit it wasn't like I was trying to drop a note a it was just just to demonstrate what you could do with raw machine code with an understanding of it so um this at least least I had a screenshot of like one of the crucial parts of debugging the vulnerable program but what the program does and just as a point of reference if you guys wanted to play with it yourself you can so at least put a little note up here and I'll make it big affine it's also in a recent the most recent issue of 2600 these these examples are listed here but the vulnerable program is called kitty because I called it that because it's just like cat it just cats out a predefined text file which is file dot txt and it has like a limited buffer on the stack of 16 bytes like purposely naive and so final text is the the exploit for it so and to run it you just you know run kitty okay so the crucial part that I was talking about here is this move ECX yet or moving ESP to ECX and then jumping to ECX it's kind of like your typical jump ESP but indirectly we were only we weren't able to find a jump ESP anywhere so we were able to find this in our theoretical example of moving ESP to ECX and now you see XS ESP so now you can jump to ECX the crucial thing to note here though is the machine code eight BCC which is so blurry but if you were to use a tool like NASA Michelle and you typed in movie CX ESP you're not going to get eight BCC you won't that's the the thing that NASA Michelle gave us is officially what Intel says you should do but there's redundancies and I'm not really saving this for last I'll just show you the tool that I was talking about in the program guide and I'm gonna jump in and out of it but if I do move ECX ESP this is what my tool does it's like NASA Michelle and up at top it gives 891 that's what your NASA Michelle is gonna give but my tool I Rasim or the independent redundant assembler also gives one of the alternates eight BCC and and for some of the other instructions we'll see there's way more alternates for some instructions you'll have like eight variations that work so some of the tools I'm gonna use in this talk I Rasim you saw it m2 elf is another tool that allows you to program indirect machine code so I can say 3 2 C 0 is like direct machine code and it tells me what this is X or al al or I mean I can also type 3 0 C 0 you know different machine code but it's still X or al al it's not one-to-one so to go through the one to one kind of philosophy here we're looking at the add instruction in this case and this is often the Intel manual let's see a lot of screenshots from the Intel manual 0 4 is a machine code in this context for add in this context add an 8 by value or an 8-bit value to Al register so and this is what it looks like in the debug in a Evans debugger you have the 0 for 4 add in for 2 is our data that we want to add and to a land in decimal is 6 6 that you see over there and we step through one step so you see EAX has four two and that's what we want to take it up a notch let's do a increment four zero is our machine code for that and really four zero is machine code for the first register to increment which is EAX and they go in order exe dB ESP EBP ESI EDI so for one would it correspond ECX 40 would of course want to edx and it works like that so there's all of them for 0 through 4 7 that's incrementing all of our 32-bit registers unless you're 64 bit and then it's a prefix and it gets confusing but then taking it up one more level we got the move instructions so it's kind of like increment where we have B and then 0 1 2 3 after the B is what a register it corresponds to and then we also add the immediate byte we want to move into the register so the registers for this one being that there are 8-bit values those are the registers in order and this is our variations of that so we have B 0 for a lb 1 for a CL and that's what the machine code looks like corresponding however this to the left is that original screenshot and to the right we have the same assembly but completely different machine code and the reason for that is in the manual we have a different encoding we can use we can move an immediate 8-bit value into a register or a pointer but because we have the option of a pointer or a register we still have a register and hence the redundancy so it's our like simple example of how it's not one-to-one now I'll cover probably the most complicated and one of my favorite examples of it not being one-to-one or the abstractions so the assembly in this example is too high level the Machine codes even to a level high level and so is the the mathematical concepts that we're trying to demonstrate with this instruction or how to you know do math and base 1 and base 0 because that makes sense so this is what this instruction is supposed to do I'm by default it takes these like a 2 byte value it splits them up and we're not really adding them together we're kind of like smashing them together to like we're taking the BCD values and making it together as 7 9 and the hex value for F of that is what goes back into that register in this case it's a X so the result goes into the AL register so that's what it does it's supposed to do but you know it's like BCD like we have a by for each value that could go away above 10 and weird things like that and another weird thing is it's it's a base 10 conversion but in this case you know D 5 is a a D and then we get this a 0 a that shows up after it that we don't actually get to say in assembly language but machine code you can intel says you can do that too but you have to do in machine code so we can mess around with that and do different bases which is kind of cool so let's do that base six we have a couple base 6 of values that are valid we smash them together like that that's the hex value of it and it goes in like that and there's a screenshot of it I of course I step through so you see that that value actually does show up in EAX the 1 7 base to this is even easier you know 1 plus 1 we get that 1 1 together that's 3 you know we put that back in there and you know that works too so now let's good ignorant we're gonna use invalid values so 0 5 & 6 F like 6 f is based something really really high in this case it's not hex it's like if you can imagine 6 like that value that the hundreds up that would be you'd have to have that many symbols for it so we take those values separately we kind of add them together I don't know how to visually represent that but that's the closest I get for that and then by the process of magic we get a 1 and it goes in there and that's actually what happens not an error that's what happens well get to why in a second but let's try base 1 because that's that's a thing we split those values up I don't have its base 1 I don't know 0 is only valid character right we split them apart happen together we get 0 I mean whatever that's like no surprise there but that's what happens for that but I mean like what about base is 0 like what simple to even have 4 bases here oh so I just I don't even what to choose I just put beef in for my value and you separate those out add them together and by the process of magic you get EF and you know that's actually what will work on the processor so like why is this happening and it is though this is intentional so we're we get into like micro code although until only gives you the pseudo code which is why it's hard to trust what's actually going on under the hood but to simplify it because that's a little bit too obscure al it gets a H times the base that you supply plus ale it's all it's doing and it turns out that that abstract mathematical concept is converting bases which is kind of profound in a way it also shows that mathematics is kind of not reality you know and so this is us working out every single example I went through with that simple formula so it works it's it's what we wanted like if we give it the right input it actually converts bases it's kind of elegant but you know if we give it invalid crap it still does something so why would you use it no real reason but it is a kind of a new novel way to clear out the a law register I guess if you do bases euro so now I'm about to go through like 30 slides of one of the most complicated and coding mechanisms in the Intel processor it's the modern plus the CID byte it's what allows us to write assembly language with later pointers really it's the way you can encode pointers so in pointers you can have like a base register you can have a scaled register like you know EBP times 2 or something like that and you can also have a fixed offset either 8-bit or 32-bit so some examples of what you've seen assembly language like the pointer part of it is ax plus eb x times 2 eb x plus 33 ec x times a Plus this longer hex value and you know just maybe displacement they're all optional of course you have to have at least one or else what are you referring to this is what the modern table looks like and we'll get to the SIB table first but it's like a lookup table you know you line one of your operands up here and then the other operand which could be a pointer over here and you just find where two lines to in the table so we're gonna work through a lot of examples to make this clear to see the proof of concept for all these examples and we're going to use X or just to keep it consistent so you know what the 3 1 and all these machine code examples refers to and by that I mean this 3 1 up here alright so our example is X or EAX with EDX so the EDX I'm talking about in the table for that second operand is this EDX here and the EAX which is not a pointer it's just a register we find it down here and if we follow it on the table we end up with this d0 over here and that started easier over there so that's how that works that's what's happening an assembler is converting it like that if we do X or e CX as a pointer in EAX then first of all we have this e ax DX appear for the second operand and we got to locate ECX as a pointer and we find it here and that would give us the mission code of zero one after our 3 1 XOR and that's our machine code up here so we're just like kind of ramping it up getting more complicated as we go our pointers say is ESI + 0 x4 t2 + EI X is going to go into that pointer so first of all on the easy part that yeah X up there now we need to find this this second section here is the one that has all the 8 bit displacements because that's the displacement we're using and then we got to just find that one that's ESI so 8-bit displacement psi so that's what gives us our four six and machine code here and that's why we have our 3 1 4 6 and then 4 2 is just referring to that part right there now for to you and then get more complicated this is kind of like the previous example only we're doing a 32-bit displacement not an 8-bit I only included it because I wanted to show endianness so first of all there's the ESP part that's easy and then EBX plus a 32-bit displacement and it's our a 3 right here so we have our 31 a 3 up here and then you notice I have like FFF elite you see it kind of backwards there that's Intel being little-endian I think it's a little endian and it's I call it reversed Indian myself because it doesn't make sense if I'm a guy that learned on motorola at all it's the the right way in my mind so then there's XOR with just a one displacement here I have EAX up here and this is where I can do just a displacement we don't have the option to do an 8-bit displacement we do have 32 bits which is fine because we just Pat it with zeros and that's where you have we have our 31 right here and then we take that 5 from the machine and that's our five there and then our zero zero zero reverse and our four to at the end so that's that I'm almost done with these really tedious examples I just want to show you how like kind of complicated it can get in this case we're going to do scale this means that we're gonna have to use the SIB table after the the motto M that's scaled meaning EC x times four so first of all X that second one that's easy and then we know that we're gonna have a bit displacement we know we're gonna do a ECX scaled this - - thing is what means use the SIB table so this is the the - - that has 8-bit displacement which is what we want and then we'll deal with the rest the the EBX ECX then the SIB table so here we are on the SIB table a different table EBX we select up here for that first dbx and ECX times 4 we find there and that's how we do that we get our 8b right there and that's how we have our 3 1 4 4 from the mod RM table 8b from this sub table and 4 - from this displacement it seems complicated but like it's so logical you're just looking this stuff up on a table now we're gonna get a little bit complicated we're going to poke through the exceptions first and then we're going to go through some of the redundancies so first of all ESP say we want to encode that you'll notice we don't have a register for ESP here so we have to do a little kind of a hack it's hard to call it a hack because I mean it's officially to do it but we're gonna use a sip like this - - to go to the sip table and then in this case we can say for a scaled register there is none but when we say none for our base register and said we do have ESP in this one and that's how we do that hack so we have our three one for X or O for from the Mataram table and then two for from this table and the question one question that I first asked when I'm looking through this encoding it manually is we have this none here but what's the difference between that none and this none and that none and that none because we're not scaling any registers so it like it doesn't matter that's like literally saying none what's the difference none and that was us using the SIB table as a hack to put in a base register with no scaled register but we could do that with other registers other than ESP so that was this is just doing with Dax so the first instruction there is how you should encode that 3 100 but these are all the other alternative ways to deal with the SIB byte I mean of course an assembler is not going to do that because that's more bytes you know how about scaling the ESP register nope you just can't it's impossible if you try to do it in an assembler it's going to give you an error it's interesting you know it's like a general purpose register that you can't scale with and we'll run into complications with that too another example is say we want to scale EI x times 2 and a DB p 2 it will you BP is kind of weird too it's in this case we we can't use this this other format down here we really are using the SIB byte to do this so for 4 we're doing EI x for that and we're going to use for 4 for the machine code to go to the SIB byte in this case we have e^x times 2 which we find here and this asterisk means this so in this case i from the modern m table i use the second encoding which refers to this displacement 8 + EBP which is how we get the EBP over here and it's actually doing a displacement of nothing that's how an assembler chooses to encode that it's not straightforward that we're getting into that territory there's an implied scale of times 1 because this is technically valid assembly that an assembler will look at but it's kind of BS in the back end what really is supposed to be happening here is EI x is the base register and ec x is a scaled register just in this case it's x 1 so that's how it encodes it it still needs the CID byte to encode that or say we have EC x times 1 well we could encode that with the SIB byte if we were doing it manually but your assembler is not going to do that it's gonna interpret we're doing it's going to do a little dance and it'll actually encode it as EC X is the base register without even using this sim byte then ESP times 1 well you know I said you can't scale ESP so you think you can't do that if you were to write this in their assembler you're gonna get an error but if you're gonna write ei X + e SP x 1 it'll actually work because your assembler is gonna I mean NASA Mizzell and I you um it might just make SP the base register instead and then scale EAX times 1 because that's valid like the commutative property and sometimes it just ignores you and chooses less bytes you know like with that community property example this is me just showing how you can switch EBX ECX and you get a different machine code in that case but logically it's the same thing EB P you can do it but the machine code is going to be a little bit bigger because EBP is encoded a little bit weird as I showed before and ESP you just can't do it because in one case it would have to be forced to be scaled which is impossible another little trick for redundancy is put an OL in it so in this case these two assembly instructions look the same but they're not one of them I'm using an encoding with a 8-bit displacement of nothing and then you can do a 32-bit as well you know it's just nothing and then you can do commutative and mix-and-match and you know put an OL in it and you got all the kinds of redundancies and that's kind of the point of this whole talk you got rip done in season different ways to do things another basic redundancy is the mod or M we're done in C this plays in is you have with instructions where you're moving things around or doing logical operators you cannot do a memory to memory operation you have to either do a register to a register or a register to memory or memory to register but not memory to memory so that's why they have to include two different encodings in the case of this like for compared three B's than coding for moving a register or a pointer into a register and then the second 1 3 9 is moving just a register into either a register or a pointer because of register can be encoded in both you got a redundancy and this is actually the exact type of redundancy that I had in the screenshot before with that toy exploitable program that's why that work was because of this redundancy and then this is just a modern table showing that c0 encoding for the ax and BX some more interpretive dance with the SIB byte say we did EI x times 2 is it the same as e ax + e ax well to an assembler I'm just going to actually write this in source and this is what it looks like when it gets disassembled so the assembler is choosing to encode the e^x times two as B X plus the ax it's ignoring you and doing an interpretive dance the reason for that is if you were to directly encode in in machine code using the C by doing x two it actually requires more machine code to do it and I should take a step back and say all this experimentation I say that I do it directly in machine code the way I do that is with this tool that I wrote and elf that I just showed you earlier so like I could do was a three three oh four oh three 300 400 and I get that representation there this is an interactive mode so what I originally wrote this for was to write out a whole program in machine code and it actually spits out an elf executable so you can use it for that too so just spawn a reference that's that tool NASM is tolerant to your so you can write something like ax times five even though you can only do x 1 x 2 x 4 x 8 you can do x x 2 minus the ax even though - isn't the thing at all because nasa ms smart it's cool i praising assam EA x times 5 is the same thing pretty much as e^x + e x times 4 which is a thing and e^x times 2 minus e ax is just e ax and that's the thing so Nasim's tolerant to your and leave that too so now I'm kind of done with the mod RM is a big thing now I'm just going to go through all kinds of random miscellaneous loose ends and when I'm done with all that I'll talk about the tool more like a rota tool so you don't have to think about this stuff so it's automated so you can go from NASA Michelle - maybe iris and for other things first of all I'm going to talk about test this particular test encoding of moving a register or pointer to a 32-bit register this is actually not a thing there's no encoding for it although you can still write assembly like it but before I do that to show kind of an analogy compare I'm showing the two different comparison have so it looks like this is me doing both forms that you know a pointer to a register and then a register to a pointer this is a disassembling it we see it's different and everything but then we go back to this test thing so say we really did try to do in the first case a pointer to a register this is what we get the assembler gives you the same thing for both why is that well Intel doesn't have an encoding for that first one this is the only encoding that it has so why is that well with compare and test compare is like a subtraction but it doesn't do the subtracting it just sets the flags test is like an and but it doesn't do the ending it just sets the flags compare if we were to look at doing a subtraction if we do 5 minus 3 or 3 minus 5 like we switch them around the result is different whereas with test if we switch those around it's the same thing either way hence why you only need one encoding and then this is just kind of a miscellaneous 64 bit trick earlier I was saying how with increments it's like 4 0 through you know 4 7 well if you're 64-bit that 4 0 through actually 4f is actually a prefix that modifies the instruction after it no for that let's talk about fencing which i think is kind of like a semaphore but it might be completely off on that because I've never used this defense instruction but this is our Intel like manual screenshots of the machine code for Elephants s fence and M fence and this is me writing those instructions and then I'm you know disassembling it and this is a result I get this is logical this is the machine code that the manual gave but then there's also this so if I go in here we have like a bunch of L offenses and you'll notice that like the first parts the same and then you got EI e 9 e AE B and the same kind of thing with other ones it's like it starts with this f0 and just kind of increments from there this is normal this is fine says Intel it's not a weird thing that I discovered Intel says you can do it so I did it and it works and I don't know why it's there but it works so you can write some more machine code that you can't assembly because it's Emily's too high level so here's another thing to make things easier for the programmer or actually more kind of enough not for the programmer for the processor it's less bytes because it's so common to compare a value with the AL register and ax and e ax there's a specific encoding just for it so even though you can do an 8-bit register or 16 or 32-bit with a register or a pointer in this kaal so popular that it gets its own machine code but as you were probably guessing now of course you can encode al with that so because of that here's some more redundancies similar to that with rotating instructions and bit shifting instructions it's really common to shift by just one even though they have the encoding here to do an 8-bit value like you can shift by with weirdly enough you can shift a full like 255 values which doesn't make sense for a register that's like you know I'm too small to actually make a difference for that but anyway same kind of thing it gives me more redundancies here there's also branches where there's no reason I'd ever want to use it other than the fact that Intel says there's no mono monix for it so of course I want to write a branch hint because I can't write a branch in assembly a branch in is just a prefix that you put in front of any instruction that would branch so in this case I put the 3 in here and it tells the processor that you know that hints the processor that there might be a branch but I don't even know if it's even used anymore but whatever you can so I really like this one because in the manual this instruction machine code wise doesn't exist but it does to me it does so this is writing an example just in source here and the reason that Intel doesn't have an encoding for the shifter with metic left is because it's logically the same as just shift left so they didn't really only use one encoding for it so if I try to do a move and then this shift left and this shift arithmetic left when I disassembled it my ships that I had both got converted to a shift left if we look to the Intel manual and look at the Machine encoding for it it is identical for both of these instructions that's weird and not that for that /for thing you saw is really represented by this binary 1 0 0 and they throw this sh l and s al on the same part of the table and then what I see though and what some of you might be seeing if you're sitting close enough to see this table is there's a blank spot over here and I'll make note of this number 6 so I'm gonna try to do it manually here this is making that instead of slash for making those four bytes or making that that four part of the bite a six and I now have SAT L and here's all the different versions of it so now I can do sa l some mission accomplished with that there's a hidden test I like looking at these tables and seeing empty things to try to see what it actually does it is well this blank part here is actually just a test just like the one right next to it although some disassemblers can't even disassemble it on me using the EDB it just says it's a data word and then there's a move right after it we're really this is actually machine code for test EAX and this move isn't even a move it's actually the operands for that test instruction and when you step through it and execute it executed it actually does run as a test so if you're looking at this disassembly you'd be mistaken at what it actually does there is no move I call this set of slides load ineffective address even though the instruction really means load effective address and what it really does I'll zoom into this instruction here is it doesn't really treat this as a pointer normally it just kind of does in mathematical operations so whatever is in our ax whatever is in our BX adds them multiplies our bx times 8 and adds 10 to this I mean this is how I wrote this instruction but you can use any pointer math you want and then it takes whatever that value is and literally puts it in EAX and that's what that's used for so in this case like our ax you know it's 5 where I'll start with our bx r bx is 30 times 8 plus 10 plus 5 will get you 255 and that's why when i ran through all the way we have FF 255 as a result that's what it's supposed to do but really to do this kind of instruction it assumes that the second operand is a pointer and it assumes that the first operand is register if you write anything else it's not going to work and it's going to give you an error so you know if I try to do something else because of course I want to try to do the wrong things I'm a hacker I want to see what the wrong things do so I type l EI EI x EI X and I get an error but this is using the mod or M table to encode it of course in machine code you can still write it the wrong way which is what I did and my debugger tells me this is invalid and I actually get a legal instruction fault error so I mean this garbage it screws up but the cool thing to me at least is that I can write something that I couldn't in assembly even though it like it will crash it's still kind of cool and then this is the last major section of this talk about redundancies its prefix abuse and it's kind of one of my favorites so first of all a byte swap it's an instruction that allows you to swap all the bytes like 8-bit values in one register and really you only have the option of doing a 64-bit register or a 32-bit register you think why can I do a 16-bit register because there is at least two bytes in it you would be able to just swap them you can do it with exchange if that's what you really want to do but like in my head I'm like why can't I deal with a you know a B swap so anyway I tried to write it anyway because I want to do the wrong things so ax is a 16-bit register I try to do it and you know of course I get in there but there's actually if you're writing assembly if you write 32-bit operations or 8-bit operations there is machine code dedicated for those but if you want to do a 16-bit operation there's you're actually using the machine code for a 32-bit operation and then there's a prefix that is put in front of it that overrides that into being 16-bit and it's used a lot there's the six six and six seven prefixes so that's how we get B swap ax but yeah like a lot of other hacks like this turns out it doesn't actually swap the bytes it doesn't do nothing though and it doesn't give an error what it actually does is clears out the ax registers so again yet another clever way to clear out it the X register but it's still kind of interesting because it's a way to clear it out that actually does a thing and it does it consistently but you can't do it in an assembly although you can you know XOR ax with ax or moves your own ax or whatever then there's also the repetition prefix this is mostly for string operations you just repeat the same operation over and over and over again and it decrements the ECX register to keep track of that but if you do that that f3 prefix it's f3 and machine code if you prefix it with that turns out that it's gonna just do nothing so there's one weird exception though anybody that knows assembly which there might be a few in the room do you know what the machine code for a no op is like ninety I heard a lot of nineties yeah so with that in mind this one maybe people might not know if you do just shout it really loud do you know what the machine code for pause is show hands anybody oh you Joe it's f3 so a repetition prefix it f 3 9 0 I should see f 3 9 0 is pause so repetition prefix is F 3 machine code for no op is 9 0 which actually is just exchange exe ax which is another very weird little thing but being that that's the machine code for there's 2 different things what if I if I repeat it a no op and then just to compare I pause right below it so of course repeating a no op there's it doesn't actually repeat because it's not a string based instruction but if I do that and disassemble it I get that almost what you would expect weirdly enough but again it's it's cool when you know what's going on under the hood in in machine code you can you can do a pause in assembly by writing something ignorant like repeating a no op which is actually not a no op at all and that's you know the machine code in the Intel manual there to show the the two instructions and machine code side-by-side there you've got the nine zero as you guys know and then F 3 9 0 4 pause even though F 3 is a repeat prefix this one is totally truly there's no real good reason to do it but I love it so here's some proof of concept code from smashing the stack for fun and profit from a very old issue of frac I modified it a little bit to be 16 bit for reasons so what happens if you prefix a prefix like if I did 6 6 before 6 6 like does it overwrite again does it like double over I'd like what is it does nothing so take that into if you combine that with the fact that in x86 the maximum instruction size in it's you can have is 15 bytes if you make an instruction that 16 bytes you get in there I've tried so you can do something like that which is amazing it's the same machine code or same programs the same shell code it logically works exactly the same except it looks like that so every instruction is 15 bytes and something about that just seems elegant to me I love that because x86 is not a fixed size you know instruction set there are some architectures that are were on the the bytes of each instruction is the exact same like that propeller architecture is talking about earlier that's an example of one where every instruction actually is the same size but Intel is so confusing not that until you do prefix abuse and this is another example of repeating every instruction even though it doesn't repeat because none of these instructions are actually repeats or string instructions so you got that full offsets this is an interesting one but say we're to look at this example just XOR pointer rax plus racks and then EAX is the second operand so if I rewrite that in source and then I compile it or assemble it and I'll compile it and then disassemble it again I end up with the same kind of instruction you know you see in the assembly part it looks exactly the same but the machine code is less and why well the reason is because in the machine code up here that you don't see it in the disassembly but there is an implied 32-bit offset that happens to be normal so we put knowles in it so we can try to trick it a little bit we can well first of all you don't try to write those nulls out in my assembly although still interpretive dance it doesn't listen to you because assemblies to my level right but it seems like that's pointless why would I even go through that exercise well the reason for that is because there is a multi byte no op and they actually do abuse the modern table to do things like that to make use of multiplied instructions so I can try to replicate what Intel recommends right those end up with that which is totally not what Intel showed so that's that's garbage that's so maybe I can try to trick it and not put knowles in there so they can't you know take the knowles out and make it make it smaller it's a little bit better a little bit closer but still so really you got to write it in direct machine code but why do that when you can just repeat a bunch of prefix is good even more bytes than they give and have a weird a snob I don't know so this is just a kind of placeholder slide in the PDF version only just so you can see some of the instructions that I'm going to demonstrate but this is a part here where we go to see I wrasse some in action just to see a little bit more different instructions than this one that only gives you two things here so first of all I'm gonna start with an ADC instruction and really that instruction doesn't matter so much I'm going to show you an interesting thing that it does with the pointer so EAX eb p pi c ax and then edx doesn't matter the second one so I get this it actually does a forest community property but the official machine code is that and a redundant version of it is actually the less machine code so not always doesn't does your assembler try to reduce the machine code but that's because it's a commutative property and kind of weird you know I can do or EAX you know 50 and I get all kinds of different things for that and I'm just trying to show you like what this can do that's s fence you know it's doing that for you automatically I can do a jump if 0 4 you know 1 and there's a little bit different like different bite sizes for that I can do a bit really long one here and I don't know if like the speaker goons flagged me but I'm actually getting close to done so say you know we'll do this really long instruction here Leitz twice it so a force community of property like I'm just showing I can can take all that crap and encode it for you push you see X you know you got that they're just showing you some of the things that it can do which is kind of cool and this is not like NASA and shell where is and it's a wrapper to to NASA it is a full interpret or it's a full assembler written in Ruby and I'll give a link to it in a second lastly I just want to show a cool trick with self-modifying code one of the other applications this this isn't just for exploitation like if you can do machine code stuff at low level you can do cool tricks like self-modifying code you can do different stager like like hiding as an example but even more with this so just showing you like a simple thing like you know incrementing and decrementing with this format is really only one bit of machine code different and I show the binary difference down there which you know that's that's the effective difference of that so like if you're right self-modifying code you have this machine code here these two examples it's exactly the same machine code although when we go through it we have move sub SBB and on the first one but when you execute all the way through really it's moved sub ad XOR present self-modifying code it's actually modifying that one bit for those instructions and that trick I actually use on cactus con coming up in September in Phoenix Arizona I'm doing a little talk called boot and play it's all about 512 byte boot sector games somebody in POC or GTFO did Tetris that inspired me so I did like a Tron game I have some other friends that did some other games that I'll be shown in there goose are you here he wrote something cool yeah okay so so he's co-presenting me for that and then also I wrote a bunch of like cracked me type puzzles that are also boost suckers as well so yeah do you guys saw the tool and that's pretty much all of it I don't know if I if I have time for questions I'll take them if not the goons can shut you down but I left this is the last slide for links and you know my blog which I talked about how assemblies to high level it's my Twitter and then the two tools that I was going through so I'm assuming if there's questions there's probably going to be a microphone maybe I don't know okay shout really loud to come up close or if there's no questions that's easier for me okay Joe wants to ask a question which is going to be terrible what's what's your question Joe I don't have any more info I don't know why Oh try it it might I haven't done anything with Ida yeah okay no I will he was asking if doing these tricks confuses Ida Pro so I haven't really played around with that because for me those kind of things don't interest me as much but on it might but I know Ida Pro is really really good at detecting so it might not trick Ida yeah you okay so that answer the question was there ever a point where machine code was one-to-one with assembly for Intel or x86 I I don't know but it's if it was it was a long time ago because a lot of these weird things that I was going through is because of all the backwards compatibility but really I do want to say no just because at the at the top of my head one of the first things that I think of is that that thing where you can't do a memory to memory operation so you have to have those two different encodings and because of that you have that redundancy so for that reason alone I would say probably no but that doesn't mean I mean for other architectures like propellers specifically I can almost say that it's 100% one-to-one there's a couple like weird things that like there there's like a little bit of difference but it I still would say technically that that makes it not one-to-one so because of that I love propeller it's weird there's no interrupts it's it's like a really weird architecture there's like no stack and all that kind of stuff but is there any other questions trying to good time ok time I'll be in the hangout room if you guys want to ask other things thank you thank you [Applause]
Info
Channel: DEFCONConference
Views: 45,866
Rating: 4.8627453 out of 5
Keywords: DEF CON 2017, DEF CON 25, DEF CON, DC25, hackers, security conference, XlogicX, Assembly Language, x86
Id: eunYrrcxXfw
Channel Id: undefined
Length: 45min 14sec (2714 seconds)
Published: Thu Nov 02 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.