Machine code monkey patching

A monkey patch is a way to extend or modify the runtime code of dynamic languages (e.g. Smalltalk, JavaScript, Objective-C, Ruby, Perl, Python, Groovy, etc.) without altering the original source code.

Wikipedia

For example, the Python code:

# someone else's class
class TheirClass:
 def their_method(self):
  print "them"
obj = TheirClass()
obj.their_method()

# our function
def our_function(self):
 print "us"

# the monkey patch
TheirClass.their_method = our_function
obj.their_method()

…will print:

them
us

…showing that we have changed the behavior of TheirClass objects, including those we didn't create ourselves. Which can't be done with more civilized techniques like inheritance.

Here's how you can monkey patch machine code, assuming the machine architecture is ARM:

typedef void (*funcptr)();

void monkey_patch(funcptr their_func, funcptr our_func) {
  ((int*)their_func)[0] = 0xe51ff004;
  ((int*)their_func)[1] = (int)our_func;
}
//monkey patching the memory allocator:
monkey_patch((funcptr)&malloc, (funcptr)&our_malloc);
monkey_patch((funcptr)&free, (funcptr)&our_free);

This overwrites the first instruction (32-bit word) of their_func with 0xe51ff004, which is the ARM machine code corresponding to the assembly instruction LDR PC,[PC,-4] – which means, in C-like pseudocode, PC = *(PC+4), or "jump to the program location pointed by the next word after the current program location".

(Why the byte address PC+4 is spelled in assembly as PC-4? I recall that it's because an ARM instruction at address X actually gets the value X+8 when referencing PC. Presumably because it is – or at some point was – the most convenient semantics for pipelined hardware to implement:

  • when the instruction at address X executes,
  • the instruction at address X+4 is decoded, and
  • the instruction at address X+8 is fetched

- so the physical PC register could very well keep the value X+8.)

So the first word of their_func is overwritten with, "jump to where the second word points". The second word is then overwritten with our_func, and we're all set.

Purpose

I actually did this in production code, on a bare metal target (no OS – just a boot loader that runs a massive single binary). I monkey patched the memory allocator – malloc, free, calloc, realloc – and the Unix-like I/O functions underlying that particular compiler's <stdio.h> and <iostream> implementation – read, write, open, close, creat. The memory allocator had to be changed to work on the target dual-core chip. The I/O functions had to be changed to use our drivers, so that we could write stuff to the Flash or USB using FILE* or ofstream.

A more civilized approach, if you want to override functions in a dynamic library, is passing another library at run time with LD_PRELOAD or equivalent. And if the code is linked statically as it was in my case, you can override the functions at link time. The trouble is that the linker could refuse to cooperate.

(And in my case, we shipped libraries, the customer linked the program, and the guy who talked to the customer refused to cooperate – that is, to help them override functions at link time. He was an old-school embedded developer, the kind that don't need no stinking malloc and printf. The project had a million lines of code very much in need of malloc and printf. He said, clean it up. Don't call malloc on the second CPU. So I went away and monkey patched malloc anyway.

In such a case, the civilized approach is to keep trying to talk the guy into it, and then have him persuade the (even more hardcore) embedded devs at the customer's side. What I did was what managers call "an attempt at a technical solution when a social solution is needed". Or as programmers call it, "avoiding a couple of months of pointless discussions". Being neither a full-time programmer nor a full-time manager, I don't have a clear opinion which viewpoint is right. I guess it depends on how long and pointless the discussions are going to be, versus how long and pointless the code working around the "social" problem will be.)

In theory, machine code monkey patching could be used in a bunch of "legitimate" cases, such as logging or debugging. In practice, this ugly thing is probably only justified in inherently ugly situations – as is kinda true of monkey patching in general.

Pitfalls

My example implementation for the ARM assumes that a function has at least 2 instructions. An empty ARM assembly function can have just one (jump to link register). In that case, the first instruction of the next function will be overwritten. A more sophisticated version of monkey_patch() could stash the target address someplace else, and use a LDR PC,[PC,clever_offset] command instead of a constant LDR PC,[PC,-4] command.

Overwriting machine code instructions breaks code that reads (as opposed to "executes") those instructions, counting on the original bit patterns to be stored there. This isn't very likely to be a problem with actual ARM code, unless it was written by Mel.

On any machine with separate and unsynchronized instruction and data caches, overwriting instructions will modify the contents of the data cache but not the instruction cache. If the instructions happen to be loaded to the instruction cache at the time of overwriting, subsequent calls to the monkey-patched function might call the original function, until the instruction cache line keeping the original code happens to be evicted (which isn't guaranteed to ever happen).

If your luck is particularly bad and the two overwritten instructions map to two adjacent cache lines, only one of which is loaded to the instruction cache at the time of overwriting, a call to the monkey-patched function might crash (since it'll see one original instruction word and one new one). In any case, on machines where caches won't sync automatically, one should sync them explicitly to implement self-modifying code correctly (I'll spare you my ARM9 code doing this).

If your OS places instructions in read-only memory pages, overwriting it will not work unless you convince the OS to grant you permissions to do so.

C++

C++ virtual functions can be monkey patched more similarly to the typical dynamic language way. Instead of modifying instructions, we can overwrite the virtual function table.

Advantages:

  • more portable across machine architectures – the vtable layout doesn't depend on the machine
  • no cache syncing problems
  • no encoding-related corner cases like very short functions or instructions used as data

Disadvantages:

  • less portable across compilers – ARM bytecode is the same with all compilers, vtable layout is not
  • fewer calls could be redirected – some compilers avoid the vtable indirection when they know the object's type at compile time (of course inlined calls won't be redirected with either technique)
  • only virtual functions can be redirected – typically a minority of C++ class member functions

The need to fiddle with OS memory protection is likely to remain since vtables are treated as constant data and as such are typically placed in write-protected sections.

Example C++ code (g++/Linux, tested with g++ 4.2.4 on Ubuntu 8.04):

#include <sys/mman.h>
#include <unistd.h>
#include <stdio.h>

template<class T, class F>
void monkey_patch(int their_ind, F our_func) {
  T obj; //can we get the vptr without making an object?
  int* vptr = *(int**)&obj;
  //align to page size:
  void* page = (void*)(int(vptr) & ~(getpagesize()-1));
  //make the page with the vtable writable
  if(mprotect(page, getpagesize(), PROT_WRITE|PROT_READ|PROT_EXEC))
    perror("mprotect");
  vptr[their_ind] = (int)our_func;
}

class TheirClass {
 public:
  virtual void some_method() {}
  virtual void their_method() { printf("themn"); }
};
void our_function() { printf("usn"); }
int main() {
  TheirClass* obj = new TheirClass;
  //gcc ignores the vtable with a stack-allocated object
  obj->their_method(); //prints "them"

  monkey_patch<TheirClass, void(*)()>(1, our_function);
  //some_method is at index 0, their_method is at 1
  //we could instead try to non-portably get the index
  //out of &TheirClass::their_method

  obj->their_method(); //prints "us"
}

Conclusion

Let's drink to never having to do any of this (despite the fact that yes, some of us do enjoy it in a perverted way and feel nostalgic blogging about it).

99 comments ↓

#1 Z.T. on 04.29.11 at 4:34 am

The calling convention for "void our_function(void)" and "void TheirClass::their_method(void)" are not the same – the member function has an implicit *this argument. Depending on architecture and compiler, overriding one with the other might not be safe (suppose caller pushes *this and expects callee to pop *this and your function doesn't).

#2 Yossi Kreinin on 04.29.11 at 4:47 am

@Z.T.: agreed; I thought about passing a TheirClass* to our_function, but then figured that I'd either want it to use the pointer (and then I'd also want to change the Python example to do so), or to explain why I passed it, and decided to leave it that way for brevity.

You're right that this could break on some platforms – although the typical caller/callee responsibilities will usually allow this sort of thing. At that level of discussion, another thing that is not guaranteed is that a class method calling convention is the same as the global function calling convention, so I'd have to mention that, too if I tried to more or less exhaustively list the ways for this to break.

#3 Mattia on 04.29.11 at 5:29 am

Just a typo: Theirs.their_method = our_function should be TheirClass.their_method = our_function

Ciao,

Mattia

#4 Yossi Kreinin on 04.29.11 at 5:43 am

Oh yeah. Fixed. That's what happens when you edit without trying in the REPL…

#5 Nemo on 04.29.11 at 7:56 am

I guess it depends on how long and pointless the discussions are going to be, versus how long and pointless the code working around the “social” problem will be.)

Actually, it mostly depends on how long the code will be around. (Ever notice how the answer is usually "longer than I ever imagined"?)

Pity the engineer(s) who had to maintain / debug / enhance that garbage after you left. A few hours of somebody new having to untangle your spaghetti, integrated over years or decades… Maybe a few conversations up front would not have been completely pointless?

This does not sound like a "manager" versus an "engineer" kind of question. It sounds more like a "good engineer" versus "bad engineer" kind of question…

#6 Yossi Kreinin on 04.29.11 at 8:23 am

Well, for starters, I haven't left yet :) And as for spaghetti – um, this isn't really an example of that, is it? And assuming that sometimes you do need to override a function in a statically linked program – there really isn't a terribly readable way to do it (in the "clean" case you'll need to read the build system files to figure it out – and that is arguably harder than reading an ugly, but documented runtime patching function). And even if it's clearly stated in some place that a function is overridden, it doesn't look like so at the point of call (a global C function call looks like it calls exactly what it says to any unsuspecting programmer knowing C). And then most people never care about the implementation of malloc() or write() – and those who do are probably capable of figuring out what I did, too, without much trouble.

Now regarding a few conversations up front – from the fact that I have one with you, despite the tone of your message, you can infer that I also tried a few conversations with him. I believe my judgment to stop at some point was correct, but perhaps you, who knows little about me and nothing about him, do know better nonetheless…

#7 Nemo on 04.29.11 at 9:01 am

I am just trying to imagine debugging code where "malloc()" does not call malloc(), "open()" does not call open(), etc. By the time I figured out what was going on and found the bug in the custom library function, I am pretty sure I would be cursing somebody's name. :-)

Although if you absolutely must do this kind of patching, I suppose it is a toss-up whether to do it statically at link time or dynamically like this. (I would still favor the static approach, since it would be fairly portable across compilers and CPU architectures… And when not, the failure would be far more likely to happen at compile time.)

But my main argument was readability, and you are right that static vs. dynamic patching is equally bad in that regard.

Incidentally, I believe your C++ approach will break on non-trivial classes (specifically, anything that uses covariant return types, like this).

My point is that this sort of thing is almost always an even worse idea than it appears. But then, I usually have an allergic reaction to "clever" code…

#8 Zeppo on 04.29.11 at 6:44 pm

Yeah, I agree with above post. Good luck getting a third party company to move to a malloc that is thread safe and a whole new basic library and requires overhauling their whole system. That just won't happen, and even if it did it would take forever to get the bugs out with that much code.

The link to Mel reminds me of when I learned to program, messing with the code to make the addresses come out right for everything was such a pain using dos debug. A sort of famous computer guy actually took pity on me and bought me an assembler when he heard of it.

#9 Yossi Kreinin on 04.30.11 at 1:04 am

@Nemo: Sure it'll break for more complicated cases, although apparently it could be extended to do the right pointer arithmetics, both for finding the vtables and for adjusting the object pointers – it just wasn't my point to illustrate the extent of complexity of the C++ calling conventions, only that in principle you could do it.

"The static approach" is more portable across CPUs, but less portable across compilers since linker scripts/flags/behavior aren't the same with all compilers. For starters, nothing in the C or C++ language definition says that you can legally do this sort of thing statically, so it's necessarily a compiler-specific hack. And the failure is not likely to manifest itself at compile time at all – very easily your function will just be ignored and the standard one taken, without any warning (for instance, if someone tweaked the build system and your overriding was incidentally disabled).

Regarding debugging – our malloc simply called the fairly standard and well-debugged dlmalloc, only using the right arena based on the calling CPU ID, and our I/O functions called our drivers – just the way it'd happen on Unix or Windows if we had to roll our own drivers, that is, you never know which code is called by those functions anyway, it's just that the mechanism for registering drivers differs across targets. So at the bottom line, the chance to have to debug problems in our custom allocator or I/O functions themselves were never very high.

I sort of figured your allergy… :) Well, I'm happy to tell that a few projects with this code bundled in them are in production, working and selling fine :)

#10 Yossi Kreinin on 04.30.11 at 1:06 am

@Zeppo: you learned to program in hexadecimal, since there wasn't a free assembler/disassembler around? Impressive.

#11 Mihnea on 05.06.11 at 10:47 pm

I almost shipped this kind of stuff in a PC program. I had to intercept user actions in Autodesk Maya (from a plug-in) and either record them to be played back later, or stream them live to other Maya instances. It was supposed to be a better alternative to instructional videos, but it never got released.

Since in Maya almost every user action results in running a script command, all I had to do was intercept those commands and record or relay them. Unfortunately the official mechanism for this doesn't catch everything because they cut some corners, but after some time spent in the fine company of ollydbg I found that it always ends up calling one of about 3 or 4 functions whenever the user does something, and I could grab the command string from their arguments. I located and patched those functions when my plug-in was loaded (which was fun, as they differed slightly between the 3 releases of Maya I had to support). I also had to run the original function after my hook was done, so I saved the instructions which were overwritten by the jmp opcode, ran them at the end of my function, then jumped back to the original function, after those instructions.

#12 Yossi Kreinin on 05.07.11 at 9:40 am

@Mihnea: tricky stuff. I also saved the original instructions – so that they could be temporarily restored before code that computed the checksum of .text ran, and in software reset cycles (awfully enough, the original system allocator was used to allocate a large share of stuff before ours took control – because there was no way for me to overwrite the functions before global constructors, etc. happened, again because that would require the linker script guy's cooperation; and before software reset, since code wasn't reloaded to the RAM, you had to restore the system allocator since ours wasn't used to running before main()). So there was something like a monkey_unpatch function. But I didn't have to use it at the time of the function call, so it was easier; I wonder if you could monkey patch a function in a case like yours, where you need to be calling the original version, in a general way (without checking the overwritten bytecode/call sequence/etc. yourself and figuring out how to do it).

#13 Mihnea on 05.08.11 at 12:01 am

There is one special case where this can be done painlessly: when the target function is exported from a shared object. You just patch the import table and you're done. Obviously, you won't catch calls from within the SO which contains the function, but you may not need to. There are a number of OpenGL and Direct3D debuggers which do this to hook API calls and track resources, state etc. When your function is not a SO export, creative programming to the rescue!

On a machine with fixed instruction size I suppose you can just end your hook function with some placeholder bytes followed by a jump after the overwritten bytes in the original function. Copy the original bytes in the placeholder and as long as your hook leaves the machine state the same way it found it, it should work.

On messier machines like the PC, where you would need to write a mini-disassembler to know how many bytes to copy, something like this may work:

- patch the function with a jmp to your hook, saving the bytes you've overwritten

- at the end of your function, put the original bytes back, save the return address somewhere, change it to a "rehook" function, jmp to the start of the original function

- when the original function finishes, it will return to your "rehook" function, which will reinsert the hooking jmp instruction and jmp to the saved return address

It should be noted that writing a bit of code which understands the instruction set just enough to figure out where the next instruction boundary is after the inserted jmp opcode is not too difficult (at least on PC). You can even steal it from something like kkrunchy, and it's probably going to take less time to implement than this rehooking business.

Or, assuming your CPU has a one-byte software breakpoint instruction and supports single-stepping:

- stick a software breakpoint at the top of the function

- do whatever you need to do inside the breakpoint handler (however horrid that sounds)

- put the original byte back, turn on the single-step flag, resume the function

- the single step handler will be called after the first instruction in the function, saving you the trouble of figuring out how many bytes it was. Reinsert the software break now to rearm the hook.

- man up and use printf debugging from now on, because this will confuse the hell out of any debugger. Also, "speedy" is not a word that can be used to describe the performance of this solution. :)

I guess this thing can be done even if you don't have one-byte breakpoint opcodes by repeatedly single stepping until you are past the overwritten bytes, but I sincerely hope no one has ever made such a CPU.

Or, even more repulsive stuff:

- if you have an MMU, turn off the execute bit for the page containing the start of the function and run the hook from inside the fault handler when the IP points to the location you care about.

- if you have hardware breakpoints, you can use those. The PC has 4 breakpoint registers, so with this you can hook at most 4 functions.

This is just a brain dump, I never tried any of it (except for import table patching for Windows DLLs).

#14 Semi Essessi on 05.15.11 at 2:15 am

Incidentally this is how break points and 'edit and continue' work in MS visual studio… Also, in the case of linked in calls you can patch the address rather than the code, either in the executable data or at runtime. Useful for debugging if you need the original function left intact. :)

#15 Anonymous on 06.03.11 at 12:25 pm

Wow, it's funny how paragraph formatting makes the Story of Mel look so much more… boring. Here's the version I think of as canonical:
http://www.catb.org/jargon/html/story-of-mel.html

#16 Anonymous on 05.13.14 at 12:52 am

About the C++ thing: If you only need to modify the behavior of existing objects that you did not create yourself (as in the python example at the start of the article), there should be a simpler way to do it:

Derive from TheirClass and overload their_func as desired. Then overwrite the vptr of obj with the one from an object of your new derived class.

This should be more portable as you don't need to mess around with protected memory and vtable indices. Of course you still have to assume the location of the vptr and worry about compiler optimizations.

#17 cheatbreaker download on 05.15.19 at 6:13 pm

very Great post, i actually enjoyed this web site, carry on it

#18 vn hax on 05.16.19 at 1:01 pm

Hi, i really think i will be back to your site

#19 fortnite aimbot download on 05.16.19 at 4:55 pm

Enjoyed examining this, very good stuff, thanks .

#20 Olevia Allgeier on 05.17.19 at 12:14 am

I'm pleased by the manner in which yosefk.com covers this sort of subject. Usually on point, often polemic, consistently well-researched and thought-provoking.

#21 nonsense diamond key on 05.17.19 at 7:10 am

I am glad to be one of the visitors on this great website (:, appreciate it for posting .

#22 fallout 76 cheats on 05.17.19 at 10:35 am

I love reading through and I believe this website got some genuinely utilitarian stuff on it! .

#23 red dead redemption 2 digital key resale on 05.17.19 at 3:46 pm

I really enjoy examining on this web , it has got cool article .

#24 redline v3.0 on 05.17.19 at 6:50 pm

I love reading through and I believe this website got some genuinely utilitarian stuff on it! .

#25 chaturbate hack cheat engine 2018 on 05.18.19 at 8:16 am

Thanks for this post. I definitely agree with what you are saying.

#26 sniper fury cheats windows 10 on 05.18.19 at 3:07 pm

Intresting, will come back here once in a while.

#27 mining simulator 2019 on 05.19.19 at 7:08 am

I’m impressed, I have to admit. Genuinely rarely should i encounter a weblog that’s both educative and entertaining, and let me tell you, you may have hit the nail about the head. Your idea is outstanding; the problem is an element that insufficient persons are speaking intelligently about. I am delighted we came across this during my look for something with this.

#28 smutstone on 05.20.19 at 11:47 am

Ha, here from google, this is what i was looking for.

#29 redline v3.0 on 05.21.19 at 7:17 am

I dugg some of you post as I thought they were very beneficial invaluable

#30 free fire hack version unlimited diamond on 05.21.19 at 4:34 pm

I conceive you have mentioned some very interesting details , appreciate it for the post.

#31 nonsense diamond on 05.22.19 at 6:24 pm

I have interest in this, xexe.

#32 krunker hacks on 05.23.19 at 6:42 am

Very interesting points you have remarked, appreciate it for putting up.

#33 bitcoin adder v.1.3.00 free download on 05.23.19 at 10:22 am

Good Morning, glad that i saw on this in bing. Thanks!

#34 vn hax on 05.23.19 at 7:05 pm

This helps. Cheers!

#35 eternity.cc v9 on 05.24.19 at 7:53 am

Respect to website author , some wonderful entropy.

#36 ispoofer pogo activate seriale on 05.24.19 at 6:23 pm

yahoo got me here. Thanks!

#37 cheats for hempire game on 05.26.19 at 6:37 am

Enjoyed examining this, very good stuff, thanks .

#38 iobit uninstaller 7.5 key on 05.26.19 at 9:22 am

Hello, i really think i will be back to your page

#39 smart defrag 6.2 serial key on 05.26.19 at 3:43 pm

Enjoyed reading through this, very good stuff, thankyou .

#40 resetter epson l1110 on 05.26.19 at 6:27 pm

I truly enjoy looking through on this web site , it holds superb content .

#41 sims 4 seasons code free on 05.27.19 at 7:44 am

I was looking at some of your articles on this site and I believe this internet site is really instructive! Keep on posting .

#42 rust hacks on 05.27.19 at 8:14 pm

Enjoyed reading through this, very good stuff, thankyou .

#43 strucid hacks on 05.28.19 at 10:33 am

Respect to website author , some wonderful entropy.

#44 expressvpn key on 05.28.19 at 7:35 pm

Just wanna input on few general things, The website layout is perfect, the articles is very superb : D.

#45 ispoofer pokemon go license key on 05.29.19 at 8:50 am

very Great post, i actually love this web site, carry on it

#46 aimbot free download fortnite on 05.29.19 at 12:50 pm

Intresting, will come back here more often.

#47 vn hax on 05.30.19 at 6:30 am

I really got into this website. I found it to be interesting and loaded with unique points of view.

#48 xbox one mods free download on 05.31.19 at 1:04 pm

Hello, happy that i stumble on this in bing. Thanks!

#49 fortnite aimbot download on 05.31.19 at 3:47 pm

I conceive this web site holds some real superb information for everyone : D.

#50 mpl pro on 06.01.19 at 6:38 pm

Hello, google lead me here, keep up great work.

#51 hacks counter blox script on 06.02.19 at 6:46 am

Cheers, great stuff, I enjoying.

#52 vn hax pubg on 06.03.19 at 10:35 am

Intresting, will come back here later too.

#53 roblox mod menu on 06.17.19 at 6:32 am

Enjoyed reading through this, very good stuff, thankyou .

#54 proxo key generator on 06.19.19 at 11:50 am

Great, yahoo took me stright here. thanks btw for post. Cheers!

#55 vn hax download on 06.20.19 at 8:30 pm

Hi, here from google, me enjoyng this, will come back soon.

#56 nonsense diamond download on 06.21.19 at 9:34 am

This is awesome!

#57 badoo superpowers free on 06.23.19 at 6:58 pm

Your website has proven useful to me.

#58 gx tool pro on 06.24.19 at 5:03 pm

Very interesting points you have remarked, appreciate it for putting up.

#59 free online Q & A on 06.25.19 at 7:00 am

I like this website its a master peace ! Glad I found this on google .

#60 geometry dash 2.11 download pc on 06.25.19 at 9:40 pm

Me like, will read more. Thanks!

#61 skisploit on 06.26.19 at 8:18 am

I was looking at some of your articles on this site and I believe this internet site is really instructive! Keep on posting .

#62 ispoofer key on 06.27.19 at 7:37 am

I am not rattling great with English but I get hold this really easygoing to read .

#63 synapse x serial key free on 06.27.19 at 10:29 pm

Thank You for this.

#64 strucid hacks on 06.28.19 at 9:13 am

I like this website its a master peace ! Glad I found this on google .

#65 serial advanced systemcare 11.5 on 06.28.19 at 2:40 pm

Appreciate it for this howling post, I am glad I observed this internet site on yahoo.

#66 cryptotab hack script free download 2019 on 06.29.19 at 9:20 am

I must say, as a lot as I enjoyed reading what you had to say, I couldnt help but lose interest after a while.

#67 cryptotab balance hack script v1.4 cracked by cryptechy03 on 06.29.19 at 3:40 pm

Found this on yahoo and I’m happy I did. Well written post.

#68 hack appkarma on 07.01.19 at 10:20 am

Just wanna input on few general things, The website layout is perfect, the articles is very superb : D.

#69 fortnite cheats on 07.01.19 at 9:03 pm

I kinda got into this site. I found it to be interesting and loaded with unique points of interest.

#70 free cheats for rust on 07.02.19 at 9:07 am

stays on topic and states valid points. Thank you.

#71 redline v3.0 on 07.02.19 at 2:24 pm

Appreciate it for this howling post, I am glad I observed this internet site on yahoo.

#72 vnhax download on 07.03.19 at 8:37 am

I was looking at some of your articles on this site and I believe this internet site is really instructive! Keep on posting .

#73 cyberhackid on 07.03.19 at 8:33 pm

Appreciate it for this howling post, I am glad I observed this internet site on yahoo.

#74 vehicle simulator script on 07.04.19 at 8:34 am

I really enjoy examining on this website , it has got great stuff .

#75 how to do seo on 07.04.19 at 1:37 pm

Parasite backlink SEO works well :)

#76 subbot on 07.04.19 at 8:23 pm

I truly enjoy looking through on this web site , it holds superb content .

#77 open dego on 07.05.19 at 8:37 am

Appreciate it for this howling post, I am glad I observed this internet site on yahoo.

#78 tom clancy's the division hacks on 07.05.19 at 8:57 pm

I have interest in this, danke.

#79 synapse x on 07.06.19 at 7:41 am

I like this site because so much useful stuff on here : D.

#80 gx tool uc hack apk on 07.06.19 at 11:53 am

Enjoyed examining this, very good stuff, thanks .

#81 rekordbox torrent download on 07.07.19 at 1:03 am

I have interest in this, xexe.

#82 call of duty black ops 4 pc license key on 07.07.19 at 10:23 am

Enjoyed reading through this, very good stuff, thankyou .

#83 spyhunter 5.4.2.101 crack on 07.08.19 at 10:43 am

I must say, as a lot as I enjoyed reading what you had to say, I couldnt help but lose interest after a while.

#84 Lesangent on 07.08.19 at 8:53 pm

Caracteristicas Propecia Liquid Amoxicillin For Kittens Allpharmacy [url=http://sildenaf75.com]viagra[/url] Discount Acticin Drugs Real With Free Shipping Cod Only Meglio Viagra O Cialis Levitra On Line Sale

#85 fps unlocker on 07.09.19 at 12:25 pm

I kinda got into this site. I found it to be interesting and loaded with unique points of interest.

#86 Lesangent on 07.14.19 at 7:42 pm

Comprare Cialis Generico In Farmacia Achat Cialis Pharmacie En Ligne Dapoxetina Vademecum [url=http://cialislis.com]cialis prices[/url] Keflex Equivalents Propecia Non Funziona Comparatif Viagra Procalis Levitra

#87 legalporno on 07.16.19 at 12:13 am

great advice you give

#88 nikki_waine on 07.19.19 at 1:57 am

amazing content thanks

#89 BuyDrugsOnline on 07.19.19 at 2:57 am

This blog is amazing! Thank you.

#90 Gale Ramnarine on 07.19.19 at 5:59 am

Skyking, Skyking, this note is your next piece of data. Immediately contact the agency at your earliest convenience. No further information until next transmission. This is broadcast #4947. Do not delete.

#91 Lesangent on 07.20.19 at 10:29 am

Combivent Inhaler Without Rx Propecia Androgenos Comprar Cialis Con Garantia [url=http://banzell.net]buy viagra online[/url] Viagra Marocain Plante Medicinale Poor Nutrition Propecia

#92 how to hack prodigy on 07.21.19 at 4:35 pm

Your site has proven useful to me.

#93 acidswapper on 07.23.19 at 3:13 pm

Good Morning, bing lead me here, keep up good work.

#94 dzate cougar on 07.23.19 at 10:48 pm

I am 43 years old and a mother this helped me!

#95 date cougard on 07.23.19 at 11:31 pm

I am 43 years old and a mother this helped me!

#96 pphud download on 07.24.19 at 3:31 pm

I dugg some of you post as I thought they were very beneficial invaluable

#97 ezfrags on 07.25.19 at 5:49 pm

This is interesting!

#98 Lesangent on 07.26.19 at 7:04 am

Getting Viagra Fast. How Good Is Amoxicillin For Viagra 100mg Testberichte [url=http://levipill.com]levitra samples[/url] Propecia 4 Month Herbal Propecia Stop Hair Loss Cialis France Pas Cher

#99 ezfrags on 07.26.19 at 6:55 pm

Enjoyed reading through this, very good stuff, thankyou .