Programs can be modified at the binary level by understanding their machine code structure, including how to bypass memory protection, inject code through dynamic libraries, and patch function return values to change program behavior without modifying source code.
Modifying Compiled Programs: A Practical Guide to Binary Hacking
Added:using software is a lot of fun i can click a few buttons and this happens do you know how hard that would have been a few decades ago i mean sure we are currently failing a completely preventable pandemic and setting fire is the only planet capable of sustaining human life but look at these whoo yeah where were we right using software is fun but you know what's even more fun modifying software and i'm not talking about modifying its source code and recompiling it that's something for the free software foundation founded by hatsune miku in 1985 to worry about modifying source code would be too easy the hard part is getting it to build again we're not going to bother with either instead we are going to try and change the behavior of a program in its compiled form i do believe this technically counts as hacking and it's more general sense like messing around with something not in a nefarious sense like i'm hacking into the bank servers my god am i on the list now well can't make any 30 under 30 lists anymore so you know i'll take what lists i can get before we start modifying programs we must first understand what a program is and there's a lot to say about this so i'm going to simplify and hand wave through a lot of things not because i think you can't handle it but because i'm trying to keep this video short a program is like a recipe as in it's a list of instructions to follow to make something happen just like a recipe you need to follow the instructions in order and just like a recipe there's prerequisites or dependencies a crumble recipe will specify that you need sugar flour butter and some sort of fruit likewise a program that generates spectrograms for music will say i need to be able to decode compressed audio files and write images probably maybe even open windows but uh a program is a recipe for computers not for humans and technically humans wrote their own recipe which is the source code and then they ask the compiler to translate it into a recipe for computers which gives assembly and then machine code and machine code is the thing that's in exe files for example what's in those files is almost ready to execute when you start a program the file is mapped in memory and then some like processing is done and then boom it's ready to be executed by the computer if i execute i don't mean to put to death i mean to interpret a series of instructions that's right a cpu is an interpreter fight me and although that's actually very very far from the truth for the purposes of this video we will assume that the computer is just a dumb machine that just interprets instructions one at a time one after another and that's not true because the computer is trying to be fast and so in actuality it's doing a bunch of work in advance and some things in parallel but it's trying very very very hard to pretend that it's simply doing things in order so we'll just believe the lie for the time being the most interesting things a program can do is compute stuff and access computers resources a program may add numbers together for example to check if a number is larger than another number and depending on that it may decide to write a value to one place or another and there are two main places a program may write to or read from this is registers and memory registers are really fast and you have to use them when you want to add numbers or compare them for example but you also have a very limited amount of them for everything else this main memory registers have names and nowadays they're usually 64 bit wide which means you can store 18 quintillion different values in them there are bigger registers as well for floating point and simply operations but we don't need to worry about them as for memory we can think of it as an enormous book that any program can read and write from again that's mostly a lie because virtual memory is a thing and you can map files and devices into memory but again that won't come up in this video or will it and with just that we can make this happen whoo computers now we've got sort of a high level theoretical view of how programs work and it's time to require ourselves and rust because i said so my video my rules and we'll do this on linux because why not so i've already got rust installed here and it comes with cargo so if i just do cargo new it'll make a new program for me that just prints hello world that mainly rs file is the recipe for humans and you can tell because it's mostly english words rather than hexadecimal nonsense then if i do can't go run from the right directory it should print something now i said some translation needed to happen and it did but it was all handled transparently by cargo if you look inside the target directory you can see there's a debug directory and in there is our executable if we ask the file utility what kind of file it is it confirms what i just said it's an elf i mean it's an elf file which stands for executable and linkable format and now comes the fun part do we look inside i think we should we can't use a text editor for this because it's not really text instead we'll use hexel a hexadecimal viewer for the terminal it has pretty colors there is it even says elf right there in the file now i can't tell you much else just by looking at that screen because i am not a beep boop machine myself contrary to popular belief but if we use the tool like read elf which the code's the other files we can see it's divided into different sections this debug stuff some text none of this is instructions though it's not adding numbers or comparing them or accessing memory it's just how the programs file is organized now we can list symbols with nm and that's more interesting because all our functions are in there well we only have one and its name is mangled uh if we want to show instructions we need to disassemble the program to go from machine code back to assembly and we can do that with opt dump and because we don't hate ourselves we'll use intel syntax we'll disassemble just the main function and that is assembly now depending on what your background is this may range from completely mundane to super scary but be not afraid as promised most of what's happening here is just messing with numbers and memory oh and also calling functions now you can think of functions as recipes too sometimes a recipe will say you need sliced apples and you can think of it as a function whose input is whole apples and whose output is sliced apples so really a program is more like a library of recipes with an entry point like a recipe we start with and that might send us some wild goose cheese doing all kinds of other recipes [Music] if we look at the instructions we have here we have sub which is for subtraction not for bottoms uh we subtract 0x38 56 which is 7 times 8 or 7 times 64 bits from the rsp register and then we have lia which stands for load effective address and is used for both memory stuff and some calculations here it just copies something from memory into the rdi register later on we have a move which copies the constant value 0x1 into the edx register and then we have xor which stands for exclusive or here it's just used to set the value of the eax register to zero because it's the shorter the usage store than a move for that you can see the move above takes five bytes to encode but the sore is just two bytes finally we have a couple call instructions which call functions and then ret which returns okay then now that you know everything there is to know about assembly let's move on to crime okay maybe you don't know everything about assembly just from this video but you know almost enough to be dangerous for example if we open the file in a hex editor and we search for the machine code that is sort of the main function 4883 ec3848d7c24 and we replace the first byte with c3 so that instead of a sub it's a red and we'll run the x group again it prints nothing because now our main function returns immediately and just like that we have become hacker and i don't know about you but i kind of have a taste for it now i want more much much more well first of all i don't ever want to enter that dreadful hex editor again do you know how long i looked for a simple hexadata i could use from the terminal you don't want to know and no vim plus xxd didn't work for me just kept correcting the file anyway i simply don't have the time to change bytes by hand in an executable however fun it might be i want a program to do it to itself we're gonna we're gonna need two functions there there we have two functions and one of them says hi and we can verify that it's still an executable with nm and it is and we can disassemble it and it looks very similar to what main was before we've got all the classics here we've got sub leah moves oracle and red have you noticed that the sub rsp 0x38 on top is later on done by an ad rsp 0x38 that's because that's how you allocate and de-allocate memory on the stack you just change the value of the stack pointer and boom for real estate and that also explains the little rsp 0x8 we see used in lia that designates a location relative to the top of the stack we also have relative addressing going on which we don't need to worry about for now so modifying our program from itself how do we do that well first we'll need the address of say hi now rust has both const and mute pointers and since we're planning on writing to it we'll need to make it mute the as operator here is used to cast between a function type to our pointer type and the star up here the references the adder pointer and that is wildly unsafe because the pointer could point to anything so we need to do that inside of an unsafe block which is rust for i accept the consequences well that was easy so let's run it and ah segmentation fault well i guess we won't be doing any more hacking today cancel the video no no no no no no wait that's just memory protection see different parts of the program when they're mapped in memory are protected differently the instructions in the dot text section have r plus x protection they're readable and executable we can actually check that if we start our process paused using a debugger then with infoproc we can get a numeric identifier for our process and in the proc directory under the directory for our process we should have a maps file and there it shows all memory mapped files for the process it starts with our own executable file and you can see most of them are read only and only one is executable that's where the machine code is that we are trying to change so are we stuck well no this is linux we can do whatever the heck we want we just need to ask nicely to remove the protection and we could do that with the region crate so we'll just call cargo add and now we can call protect with handle now why with handle well that version gives us a guard that when dropped will restore the previous protection and that seems like a good idea before we go on and call say hi so we just keep our guard in the scope right to memory and let the guard fall out of scope which should restore the previous protection okay let's give it a shot more stack folds okay okay here's the thing we can't actually change the protection for a single byte we can only do so for a memory page and the problem is the code for the main function and the code for the say hi function are on the same page so the second our protect call returns all our code stops being executable and because our computer is masquerading as a simple machine that executes things in order it tries to execute the next instructions and go well and kabooms that's a theory because to be fair we are witnessing the exact same thing as before for all we know calling protect didn't do a damn thing but if i'm right and i am all we need to do is to change that read write to read write execute and everything should work but before we do i'd like to verify my theory it's not particularly hard let me first let's add a couple print statements and run it again okay first one prints good let's run it again but under s trace asking it to look for the mprotect system call what's a system called it's like a function call but to the system i really i really don't want to spend too long on this this protection rings and the operating system in this case linux runs in ring zero and our program runs in room three because all this runs in a vm there's even a ring minus one fun right so basically memory protection is a feature of the operating system the so we need to call from ring three into ring zero and that's the system call or just cisco all right let's see there disaster as planned we see a bunch of unrelated and protect calls then our print statement and then our and protect call which immediately causes a segmentation fault which shows up as six seg fees signal segmentation violation and we could have reached the same conclusion by simply using gdb but i really wanted to show off s3s so now that we've validated our theory let's try and apply the fix we'll change read write to read write execute and run it and it prints nothing nothing at all which is exactly what we wanted but um this is easy mode because we control everything the program we're modifying is also the program we've written ourselves and so we could just as easily change the source of say hi instead it would be a lot more fun if we could modify the behavior of another program and the easiest way to do that on linux is to use ld preload ld preload is an environment variable that is read by the dynamic linker or dynamic loader when it starts a program if you set it to the path of a dynamic library or in linux parents a shared object it'll load it into the program so let's first turn our crate into a library which we can do by adding a lib section in cargo.tamil uh which will have create type set to cdylib for c dynamic library and another creators library will want to rename main.rs to lib.rs and then build it again and now we have a dynamic library let's ask the file utility what it thinks about it and yep it's a shared object now we can preload it into say cat which is command line utility that we can use to print the contents of a file if we run it without ld preload it shows this and if we run it with ld preload it says to the path of our shared object it shows the same thing i i don't think the main function is being run which would make sense because it's no longer an executable it's just a library so we don't even know if it's actually being loaded luckily there's a way to find out if we also export ld debug to save files we can see what actually gets loaded yep our library is the first thing being loaded now we just need to be able to run some code when the library is loaded but libraries have no entry points we can't just name a function main and boom we have an entry point luckily libraries can have constructors it's not dark magic it just adds an entry to one of the elf sections we saw earlier but it's a bit annoying to set up so we'll just use crate that takes care of everything for us the ctor crate we'll have our constructors just say hello from rust so we know it's been injected properly and if we run cat again with ld preload set we see hello from rust well how old are you too so we're in cat's address space from the two we have at home i can tell you it's cute for now but it probably doesn't end well in the meantime what can we do with it well cat prints the contents of a file and it's written in c so it probably calls the open function from libsy maybe we could try and hack that first we'll need the address of open and there's a couple's way to do it but i guess because our library also links against the c library which we can check by just running ldd we can just declare an extern function again we can cast that to a constitute and print it out no it looks reasonable at the very least it's not zero and now same modus operandi we unprotect we patch and we re-protect as before we'll just overwrite the first instruction of open with the red which should return immediately it's show time let's run it and uh yeah it gets stuck well it appears stuck but it didn't stack fault that's the start you can also easily control c out of it which sends seconds the interrupt signal and it exits gracefully so what could be happening there this is not movie magic by the way i was actually stuck on this when i wrote the script for this video yes there is a script there is always a script but when messing around with it i found something interesting if we try typing something and pressing enter it repeats the output and if we press ctrl d which closes the standard input file it exits gracefully 2.
so cat is reading from std stdn exactly as if we'd called cat with no arguments at all and this is fantastic because i was struggling to find a way to talk about calling conventions and it just it just came to us see the open function from lipsy returns an integer that's just a number i promised computers were mostly messing with numbers in memory and that number corresponds to a file descriptor that we just opened if it returns a negative number it means the operation failed but anything zero or higher is just a file scripter a number that describes an open file and the way functions return values on x8664 is through the racks register so what happens if we return from the open function without changing the value of racks it thinks the return value of the function call is whatever happened to be in racks at the time and in that case because we're seeing what we type being echoed by cat it happens to be zero every process has at least three open file descriptors to start those of zero for stdn one for sdd out and two for sddr and i should verify that by running it in gdp it's a bit tricky to preload our library in ddb but we can do it easily by using args and using the end utility which is a little wrapper that allows setting environment variables it's perfect if we just run it we observe the same behavior it's good i mean sometimes but disappear under the microscope i mean inside the debugger and those are called heisenbugs now let's just set a breakpoint on open and run it again okay we've reached open let's use steppy to step through instructions and wait wait wait wait wait wait this is the actual implementation of open this is a heisenberg after all but hey this is a faster than 9 video of course i'm going to have a theory or rather i have a question for you the viewer how do you think gdb sets breakpoints now in case the demonstration wasn't clear enough a break point is a place in the code where we asked the debugger to stop execution so that we can inspect the state of the program now you've seen me step through the program instruction by instruction before so surely there's a facility to do that but that also sounds like it might slow down the program a lot it does so surely debuggers have another way to stop program execution at a given point they hack the matrix they patch the function they just overwrite it with say a trap instruction or in three which is your xcc in machine code and then because they control the process being debugged the they can catch that trap instruction and let you examine the state of the program but how does continue work then well by simply restoring the original code of function on there and you know the problem with that it's apparently restoring from the file or at the very least its own copy of libsy.so which provides open so by setting a breakpoint on open we undid our hack ggb overwrote it within three and later on restored the original code for open and we can verify that by disassembling open right after we've patched it we see the red as the first instruction and right after we've hit the breakpoint we see the original code which is in nbr 64.
destruction time does that mean we can manually trigger a breakpoint by writing an n3 ourselves let's find out we'll just change the xerox c3 to 0xcc and running it manually exits with trap very well now let's load it in gdb run it and yep it catches the trap and acts as if we set a break point there the problem here is because it's not a breakpoint gdp set itself nobody's going to restore the original code instead of the in three luckily nbr 64 is actually a rep z followed by a nope and repc is encoded as a single byte so we've effectively just ruined indirect branch tracking but not broken the program completely by the way that's not just any nope it's a nope on register edx i love how x86 is just like a nope certainly sir and on which register will you want to be noping today adx excellent choice but it's a clever trick because there's so many ways to spell nope which is no up and it's just ignored by the cpu it's used here to indicate something to newer cpus without it breaking for old cpus it's graceful degradation just like in the web okay let's make that cat fail we'll just write negative one into racks and okay actually i have no idea what the machine code for that is but no worries we'll just use an assembler for that we could use nasm but let's use the asm the psd flavored rewrite because i've never used it and i'm curious so we'll make an asm file define a fail symbol and just move minus one to the racks register and return and assemble it by calling yasm dash felf64 fail asm and it'll produce a fail.o file nm which by the way stands for named list shows a single unnamed symbol okay let's just use object on there still with intel syntax and there's our machine code it's quite a bit longer than just a red so we'll have to make it a slice insider and safe block we'll make another mutable slice that will represent the destination where we're copying the code and we'll call copy from size on the destination slice with our machine code as an argument and if we did our job correctly nothing should work anymore i wonder what cat prints when open fails bad address lol the mao okay buddy oh oh i guess that's what happens when you return a negative value without setting the er no variable it too is set to whatever the last error was i guess well i think we've all had our fun so it's about time to close up this video what's that you want more okay how about we have cat read from a completely different file instead it can't be that hard we don't even have to change much we can just open a file in our constructor retrieve its file descriptor and make open return that value all the time opening a file is as easy as file open and we can get the file scripter with azeroth fd from the azure ifd tray which is implemented for sddfs file now our code can't be static anymore right the file script are returned there could be anything so we have to mess with that machine code yasmin gave us earlier but you know i'm looking at it and i'm seeing 48 c7 c0 followed by and to me it seems like 48 c7 c0 is really the move a constant to rex part and is the constant itself which as a signed 32-bit integer look at us getting technical all of a sudden would be minus one so if we just overwrite that with the value of fd it should work okay instead of having the whole code as a single slice let's build it up as a fact first we'll have 48 c7 c0 and then our file descriptor as little indian because that's what the cpu expects and then c3 to return now is there a better way to write this almost certainly am i going to bother hell no this is bonus contents we can have a little heap allocation as a treat very well time to test our crimes do they work they do not bad foul descriptor huh why in the world would it have oh oh oh it's because ray resource allocation is initialization once we hold a file we know it corresponds to a valid open file descriptor but also when we let it fall out of scope it closes the file descriptor so i guess it's more like arctic resource destruction is cleanup damn rust safety getting in the way don't worry though there's a way around it i mean we're already removing protections and overriding cover what's one more crime rest values much like citizens of the european union have a right to be forgotten that way it won't actually run its drop implementation it's the structure if you will when it falls out of scope so just a quick std mem forget and it works hacking is so fun are we having fun we are aren't we it would be a shame if the video were to end suddenly [Music] [Music] files
Up Next

Write a Shell in C: Step-by-Step Tutorial for Beginners
@Caffeine2Code
38.2K views•2017-11-26

Solving the Heat Equation with DeepXDE and PINNs
@Dr.Mohammad_Samara
8.5K views•2023-07-17

HTTP Requests Explained: GET, POST, PUT, DELETE
@codecademy
103.1K views•2021-10-07

Enigma Machine Mechanics: WWII Encryption Explained
@JaredOwen
13.2M views•2021-12-11
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Computer Science



































![[Workshop] Saying Goodbye to the #US Stream – Analyzing String Obfuscation](https://i.ytimg.com/vi/B6lBZC6XEJo/maxresdefault.jpg)
![[Workshop] Anti-Analysis Logic – Inspecting the .cctor & Anti-Debug](https://i.ytimg.com/vi/6rcUxmRGhlg/maxresdefault.jpg)


