Embed
Email

Tutorials

Document Sample

Shared by: Kerala g
Categories
Tags
Stats
views:
7
posted:
12/7/2011
language:
pages:
14
How detours work



Practically everyone uses detours without understanding how they work, I am going to describe a standard JUMP detour

hook:



For a detour we require the following:

- the address of the original function (from now on referenced as orig_func)

- the address of the hook function (from now on referenced as hook_func)

- number bytes to overwrite in the original functon (from now on referenced as detourLen)



OK first thing I will explain is detourLen, MS Detours and some other detour classes will get this value for you

automatically.



detourLen and the JUMP

The first thing you must know about detourLen is that it must have a minimum value, in the case of a JUMP detour the

number of bytes required to do the following:



JMP



so in bytes that is:

E9 00 00 00 00 // an address is 32bits (4bytes)



(E9 is the opcode for JMP instruction)



So the minimum detourLen for this type of detour is 5 bytes.



However we cannot go ahead and just write JMP at the original function and think thats it, because we could be

overwriting half of an intruction and leaving the end half as it was - causing a crash, confused? here's an example:



Lets have a look at kernel32.dll's LoadLibraryA:

Code:

8BFF MOV EDI,EDI

55 PUSH EBP

8BEC MOV EBP,ESP

837D 08 00 CMP DWORD PTR SS:[EBP+8],0



Now remember we need a minimum of 5 bytes to write the JUMP hook, so if you have a look there the 5th byte is the END

of an instruction (0xEC) so we are not writing into an new intruction!



Therefore the detourLen for LoadLibraryA is 5bytes.



Now let's have a look at kernel32.dll's GetHandleContext:

Code:

6A 78 PUSH 78

E8 26DCF9FF CALL kernel32.SetLastError

33C0 XOR EAX,EAX



We need a minimum of 5 bytes, so we go to the end of the second instruction - FF, that is a total of 7 bytes - so DetourLen

for GetHandleContext is 7 bytes.



Why 7 bytes? Because we cannot go and do this:

Code:

E9 00

00 0000F9FF

33C0 XOR EAX,EAX



As you can see we are writing into the middle of the instruction and leaving the end (F9FF), causing a crash. So instead we

specify detourLen as 7 bytes, and the detour function will do the following:

Code:

E9 00

00 00009090

33C0 XOR EAX,EAX



The 90 opcode is a NOP instruction (it does nothing except fill space) - now the code can be executed without trying to run

half an instruction!



So what IS a detour?



Now you cannot expect to go and overwrite part of the original function and think that it will still work properly! Pay close

attention:



What a detour does is COPY the number of bytes specified by detourLen to a memory allocated place. At the

memory allocated place, after the bytes it has just copied over it inserts a JUMP back to the original function, at

original function + detourLen. The detour function returns a pointer to the start of this allocated memory,

CONFUSINGLY named the "original" in many basehooks.



Example scenario with GetHandleContext - The detour



Confused? Let me show you a scenario:



orig_func address: 0x7C86B683 (in bytes: 83 B6 86 7C)

hook_func address: 0x50607080 (in bytes: 80 70 60 50)



// Beginning of GetHandleContext untouched

Code:

6A 78 PUSH 78

E8 26DCF9FF CALL kernel32.SetLastError

33C0 XOR EAX,EAX



Like we already ascertained GetHandleContext detourLen is 7 bytes, so the Detour function will do the following:



1. Copy the first 7 bytes to a memory allocated place



// Memory allocated place

Code:

6A 78 PUSH 78

E8 26DCF9FF CALL kernel32.SetLastError



2. Insert a JUMP back to the GetHandleContext + 7 bytes (0x7C86B683 + 7 = 0x7C86B69B)

// Memory allocated place

Code:

6A 78 PUSH 78

E8 26DCF9FF CALL kernel32.SetLastError

E9 9BB6867C JMP kernel32.GetHandleContext+7



3. Save a pointer to the start of this memory allocated place



4. Overwrite the first 5 bytes of GetHandleContext with JMP and pad the remaining bytes with 90 (NOP)



// Beginning of GetHandleContext detoured

Code:

E9 80706050 JMP hook_func (0x50607080)

9090 NOP NOP

33C0 XOR EAX,EAX



5. Return a pointer to the memory allocated place



Example scenario with GetHandleContext - The hack

Now what do we do with the pointer to that memory allocated place? Well that is what is call the ORIG in many basehooks

(i.e. orig_GetHandleContext or o_GetHandleContext).



It is our job to call this "orig" inside our detour function, so our detour hook might look like this:



Code:

HANDLE hook_GetHandleContext(...)

{

orig_GetHandleContext(...);

}





So how does the scenario execute?



1. The program makes a call to GetHandleContext

2. At the begining of GetHandleContext is the jump to your hooked function

3. Your hooked function is called

4. At the end of your hooked function you call the memory allocated place where the bytes you overwrote in the original

are executed

5. At the end of the memory allocated place is a jump to the original + detourLen

6. The original function continues as normal...



(PS the NOPing isn't essential, so long as the mem allocated place jumps past those "bad bytes")









Simple CS:S Console print hook



here is something simple -



first you will need:

ollydbg

c++ compiler



ok - now you will need some assembly know-how but its pretty simple all in all.



open css - then open ollydbg ->

hit attach - hit the "E" button at the top ->

scroll down to "engine.dll" and double click ->

right click on the CPU window (main one) after you do that ->

Find all referanced text strings ->

search for text (do this by right clicking) "Unknown command" ->

the string should be "Unknown command - %s" or something similar ->

doulbe click on it and some text should be there ...mine is this:



Quote:



0DA0C93F 50 PUSH EAX

0DA0C940 68 F879D60D PUSH engine.0DD679F8 ; ASCII "Unknown command "%s"

"

0DA0C945 FF15 4055D50D CALL DWORD PTR DS:[] ; tier0.Msg

now - here is how we hook this function ->

right click on "CALL DWORD PTR DS:[]" ->

follow ->

it should look a little something like this ->

Quote:



00883250 > 8B4C24 04 MOV ECX,DWORD PTR SS:[ESP+4]

00883254 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]

00883258 50 PUSH EAX

00883259 51 PUSH ECX

0088325A 6A 00 PUSH 0

0088325C E8 0FFEFFFF CALL tier0.00883070

00883261 83C4 0C ADD ESP,0C

00883264 C3 RETN

you may or may not have noticed the original call used the sprintf() format - this is important and should be remembered.



so now we have the address 00883250 is the start of the function



so - before you just go and detour that i suggest you learn more about dynamic dlls (loaded in differant places)



we need to find the base address of of the current dll we are in (tier0.dll)... ->

itll say tier0 (or whatever dll) at the top ->

go to the "E" again, right click teir0.dll ->

copy to clipboard -> base (mine happens to be 0x00880000) ->

simple math will tell us that if the function is at 00883250 and the dll is at 0x00880000 ->

tier0.dll base + 0x00003250 = the function



ok - so now we are done, you may close css because we have some coding to do.



make 2 new files in your project - lets call them engine.cpp and engine.h (in case u wanna add more) and include all the

proper headers



now, since printing to the console uses sprintf() format - ill use a snippet from azorbix' add_log function to suit our needs -

put this in engine.h:



void pfnConsolePrint(const char *fmt, ...);

void hook_console();





now go to engine.cpp and add this (credits to azorbix and msdn):



#define console_css 0x00003250



void (*Orig_pfnConsolePrint)(const char *fmt, ...);



void hook_console()

{

Orig_pfnConsolePrint = (TYPE_pfnConsolePrint)DetourFunction(

(BYTE*)(((DWORD)GetModuleHandle("tier0.dll")) + (DWORD)console_css),

(BYTE*)pfnConsolePrint);

add_log("pfnConsolePrint [0x%X", (((DWORD)GetModuleHandle("tier0.dll")) +

(DWORD)console_css));

}



void pfnConsolePrint(const char *fmt, ...)

{

char szBuffer[1024];

bool onetime = true;

va_list args;

va_start(args, fmt);

memset(szBuffer, 0, sizeof(szBuffer));

_vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, args);

va_end(args);

Orig_pfnConsolePrint(szBuffer);

}





its also hooked now - so you can read the text passed through the buffer if u want



whenever you want to use it - simple include engine.h and do something like:



pfnConsolePrint("hello number %i \n", rand()%255);

engine.h:

void pfnConsolePrint(const char *fmt, ...);

void hook_console();





engine.cpp:



void (*Orig_pfnConsolePrint)(const char *fmt, ...);



void hook_console()

{

Orig_pfnConsolePrint = (TYPE_pfnConsolePrint)DetourFunction(

(BYTE*)(DWORD)GetProcAddress(

GetModuleHandle("tier0.dll"), "Msg"),

(BYTE*)pfnConsolePrint);

add_log("pfnConsolePrint [0x%X]", (DWORD)GetProcAddress(

GetModuleHandle("tier0.dll"), "Msg"));

}



void pfnConsolePrint(const char *fmt, ...)

{

char szBuffer[1024];

bool onetime = true;

va_list args;

va_start(args, fmt);

memset(szBuffer, 0, sizeof(szBuffer));

_vsnprintf(szBuffer, sizeof(szBuffer) - 1, fmt, args);

va_end(args);

Orig_pfnConsolePrint(szBuffer);

}





main.cpp (in DLLMAIN):



hook_console();





then anywhere u want to use it do:

#include "engine.h"



then use it like:





int num = 3;

pfnConsolePrint("omg num %i", 3);









VERY BASIC : What are detours and how are they used?

As you can see from the title, this is going to be very basic and general. There is another tutorial on detours by Sinner that

is very detailed and good for more experienced users, but the ASM tends to scare the newer people. Refer to it if you want

more detail/a different approach. Anyways, let's get started.



What is a detour?



In normal English, a detour is an alternate route to continue on a certain path. Ultimately, a detour in programming boils

down to this as well. Since we're talking normal English, I'll give you this example:

You're driving along on Interstate 1337.

You get off of the interstate at exit 133b and make a right.

You're supposed to make another right turn about 3 miles down the road on to Imaginary Lane, but there is a detour telling

you to go straight.

A mile or so down the road, the detour tells you to make a right hand turn.

Then, one block down the road another right turn.

About a mile down the road you are told to go left.

You are now on Imaginary Lane, just as you had intended, but your path to it was modified by the detour.

The difference is that you control the detours you're using.



How are detours used?



Detours can be used for almost everything.

A code-esque example:

Suppose the game you are playing has some function that only draws weapons.

This function has 3 parameters:

1. a boolean to see if the weapon is on the ground or not.

2. a structure containing the data (name, model, etc) of the weapon it is currently drawing.

3. a dword for rendering effects that is defaulted to 0x00000000, which just so happens to be completely transparent in the

game.



So far, the game function would have to look something like:

Code:

void DrawWeapons(bool bOnGround, weapon_data_s *weap, dword color=0x00000000)

{

// blah, drawing code goes here

}



You find the memory address of this function, as well as the length needed for detour (the other tutorial that tells how to do

this, no sense rewriting it)

You create your own function of the same type as said function, with the same parameters (names don't matter - types do)

You then detour the original function with your function.

After your function is called and completed, you can call the original (not required in some cases)

Do something to make sure you know that it is detoured properly (add a log, draw something, etc)



We should have something like:

Code:

void My_DrawWeapons(bool bng, weapon_data_s *wd, dword clr)

{

// this is where you do your stuff.

add_log("DrawWeapons was called!");

Stored_DrawWeapons(bng, wd, clr);

add_log("DrawWeapons detour was a success!");

}



Now that we have the function detoured, let's get on with what you want to do next.

You want to color them red when in someone's hands.

You also want them to be invisible if they're on the ground.

You check whether the guns are in hands or on the ground.

If they are on the ground, you simply return without calling the stored function.

Otherwise, you change the parameter clr to red.

In hex, 0xRRGGBBAA is the format for an RGBA value.

That means that we want to set clr to 0xFF0000FF.



For our final function we should have:

Code:

void My_DrawWeapons(bool bng, weapon_data_s *wd, dword clr)

{

if(bng) return; // We don't want to draw the weapons on the ground.

clr = 0xFF0000FF; // We are setting this to red.

Stored_DrawWeapons(bng, wd, clr);

}

[Beginner] Aimbot + Simple ESP Tutorial



Welcome to my first tutorial

After one week of playing around with counter-strike i want to show up a little ESP and Aimbot that i did just for fun.



It would be nice if you could credit me when using this code (It took me nearly half-an-hour to program this...)



Let's go:



At first we need 2 new functions: On the one hand a function to check the team of a given entity and on the other hand a

function to draw our ESP box.

Let's begin with the first one. It should be placed somewhere above your HUD_ReDraw function.



Code:

int GetTeam(char *model)

{

// Check all terror team models

if (strstr(model, "arctic") ||

strstr(model, "guerilla") ||

strstr(model, "leet") ||

strstr(model, "terror"))

return 1;



// Check all counter team models

else if (strstr(model, "gign") ||

strstr(model, "gsg9") ||

strstr(model, "sas") ||

strstr(model, "urban") ||

strstr(model, "vip"))

return 2;



// No Team/Spec/...

return 0;

}



We're searching with strstr a string inside a string. Means we are searching the name of the model inside the whole model

path.



The second function uses the pfnFillRGBA engine function to render 4 blocks that respresent our box.



Code:

void DrawBox(int x, int y, int r, int g, int b, int a, int iRadius, int iThickness)

{

int iRad = iRadius / 2;



// top

gEngfuncs.pfnFillRGBA(x - iRad, y - iRad, iRadius, iThickness, r, g, b, a);



// bottom

gEngfuncs.pfnFillRGBA(x - iRad, y + iRad, iRadius + (iThickness / 2), iThickness, r, g, b,

a);



// left

gEngfuncs.pfnFillRGBA(x - iRad, y - iRad, iThickness, iRadius, r, g, b, a);



// right

gEngfuncs.pfnFillRGBA(x + iRad, y - iRad, iThickness, iRadius, r, g, b, a);

}

iThickness stands for the width of the box border and iRadius is the radius of our box.



Now we only need to add the final function that renders our ESP on screen and moves our cursor. To gain performance I

put ESP and Aimbot in one function and for this in one loop through all players. We start the function with some globals

that are used later on.



Code:

void DoEspAim(void)

{

// Player Entity pointers

cl_entity_t *pEnt = NULL, *pLocal = gEngfuncs.GetLocalPlayer();

// Playerinfo structure

hud_player_info_t pInfo;

// Get the playerinformation

gEngfuncs.pfnGetPlayerInfo(pLocal->index, &pInfo);

// Check for the team

int iOwnTeam = GetTeam(pInfo.model); // Team holen



We define 2 entity pointers. The second one saves the information of the Local player (you) and the first one will save the

Entity while in the loop. Finally we save our own Team in iOwnTeam to prevent aiming on teammates.



After that we define some other global variables that are needed to determine the position of a player on screen in relation

to the Crosshair position.



Code:

float fScreenPos[10];

float fDistFromCenter[3];

float fCenterDistance;



// ScreenX and Y / 2

int iScreenCenterX = gEngfuncs.GetWindowCenterX();

int iScreenCenterY = gEngfuncs.GetWindowCenterY();



// Nearest player

cl_entity_t *pNearestEnt = NULL;

float fNearest = -1.0f;

float fNearestAimTarget[3] = {0,0,0};



Now we need to browse all players with a for loop (at least 32) and save our Data in the pInfo struct.



Code:

for (int i = 0; i index == i) continue;



// Get Entity and check it

pEnt = gEngfuncs.GetEntityByIndex(i);

if (!isValidEnt(pEnt)) continue;



// Read PlayerInfo and Team

gEngfuncs.pfnGetPlayerInfo(i, &pInfo);

int iTeam = GetTeam(pInfo.model);



After this we set down the Z-Coordinate of our current Player higher to let us aim on the Head. At least this is a very very

basic method for doing this. If you get more advanced you could add a Vector that saves these values to move the aim

target. A bone or hitbox aimbot would be better, too. After this we get the screen coordinates with CalcScreen (It can be

found on this forum, too.)



Code:

pEnt->origin.z -= -20; // We want the pos of the Head

if (CalcScreen(pEnt->origin, fScreenPos))

{

// He is visible

Now we need the good old phytagoras We wanna calc the distance between the player and the crosshair on the screen to

compare it with the other players that are on screen.

The formula is a² + b² = c²



Code:

// Calculate the Distance in Relation to the screen center (crosshair

position)

fDistFromCenter[0] = iScreenCenterX - fScreenPos[0];

fDistFromCenter[1] = iScreenCenterY - fScreenPos[1];



// The phytagoras without the squareroot

fCenterDistance = square(fDistFromCenter[0]) + square(fDistFromCenter[1]);



To gain extra performance i have not used the squareroot to determine the exact values cause we only want to compare

values that are calced with this code, too.



Now we draw the ESP and continue with our aimbot



Code:

if (iTeam == 1) // Team = Terror = Red

{

DrawBox(fScreenPos[0], fScreenPos[1], 255, 10, 10, 255, 25, 2);

}

else if (iTeam == 2) // Team = CT = Blue

{

DrawBox(fScreenPos[0], fScreenPos[1], 10, 10, 255, 255, 25, 2);

}

else // Everything else will be kicked out of our loop (this could be done a

little bit further, too.

{

continue;

}



Now we check if the current player is an enemy or not (which actually only matters for our aimbot).



Code:

if (iTeam == iOwnTeam) continue;



We need to compare our calced values with the current minimum values to determine the nearest player for our aimbot. If

the current player is more near to the crosshair than an old one we overwrite all needed values.



Code:

if (fNearest 0 && fNearestAimTarget[1] > 0)

{

// Define the aimsmooth factor

#define AIM_SMOOTH 3



// Is the right mousebutton actually pressed?

if (GetAsyncKeyState(VK_RBUTTON))

{

//Calculate the interpolation

float x = fNearestAimTarget[0] - iScreenCenterX;

float y = fNearestAimTarget[1] - iScreenCenterY;



x /= AIM_SMOOTH;

y /= AIM_SMOOTH;



fNearestAimTarget[0] = iScreenCenterX + x;

fNearestAimTarget[1] = iScreenCenterY + y;



//Aim on the target

SetCursorPos((int)fNearestAimTarget[0], (int)fNearestAimTarget[1]);

}

}



Well in the SetCursorPos command we could add an delay to make the Aimbot more smooth. This could be done

calculating the distance from our crosshair to the enemy (x and y values) and dividing them by a "smooth-value". Then we

could subtract them from the current values.



Finally the last function needs to be called in the HUD_ReDraw function and it should be working Before posting dump

questions make sure your EngFuncs are names exactly like mine and that you have all needed functions like isValidEnt or

CalcScreen.



At least you could add some extra stuff very easy:

- Aimthrough 0/1

- Smooth setting

- Better teamdetection (using usermessages)

- etc. etc.



P.S.: Do what you want with it, i give a shit...



P.P.S.: Finally i wanna add a little piece of code to add a very basic Panickey which is very useful.



Code:

// Every key gets an array entry

bool bKeyPressed[256];

bool IsKeyPressed(int iKey)

{

// Search for global key states

if (GetAsyncKeyState(iKey))

{

if (!bKeyPressed[iKey])

{

bKeyPressed[iKey] = true;

return true;

}

}

else

bKeyPressed[iKey] = false;



return false;

}



For using a global panic key you should add a global panic variable, too.



Code:

bool bPanic = false;



And finally add it in the HUD_ReDraw where you already added DoEspAim().



Code:

if (IsKeyPressed(VK_F12)) bPanic = !bPanic;

if (bPanic) DoEspAim();

Client Aimbots



Aimbot tutorial



Introduction:

In the past many people asked me how they could improve “their” Aimbots. An endless list of people posted this question

in various coding forums, so I thought that this tutorial might be useful to some of you.



The Past:

Many good or less good programmers have made several attempts to improve their Aimbots. Snipity was the most

successful one according to me. He invented useful features as such as “No Spread” and “Auto wall”. Most of the OGC

tweaks of today is based on his work (mostly without crediting him, not surprisingly). There were also those guys who tried

to

improve their Aimbots by replacing PI. That is the most useless effort you could ever do. The normal pi is more than

enough.



What Aimbot method shall I choose?



There are mainly three sorts of “client” Aimbots; Vector based Aimbots, Bone based Aimbots and the newest generation of

Aimbots Hitbox based Aimbots.

The oldest and most used sort of Aimbots are still vector based Aimbots. They were the first sorts of Aimbots that

functioned client side. When they were introduced they were revolutionary compared to existing Aimbots

(OpenGL & Color- Aimbots). Vector Aimbots are simple to create and very rapid. Their disadvantage is the inaccuracy.

The basic vector Aimbot covers Vectors (or aiming offsets) for two states: sitting and standing. This is what the

CS Models do most of time. So you should be fine if you use this on an ordinary anti cheating server.

But cheating on anti cheat server is not what most cheaters do. They battle each other on so called hacking

servers. Cheat vs. Cheat. A frag/round (can sometimes) take less then a few seconds. So every shot should impact 100% at

the right spot.Vector Aimbots don’t cover a solution for the model’s position between the sequences and several other

sequences

such as (duck) jumping.This was noticed by bunny771, so he made the first Bone based Aimbot which solves this problem

pretty good.

Simply because it aimed for body parts it was sequence independent. A Step back is Sequence Based Aiming.

Of course sequence based aiming is better than Vector based Aiming but it doesn’t cover support for moments between

sequences.



What really improves my Aimbot?



Before we start I’ll give you a list of things that won’t help:

“Tweaking” of the pi;

To call findtarget() like 10 times in a frame;

(Right now I can’t think of more useless stuff :-/ )



A possible way to improve your Aimbot would be to apply the visibility checks to very predicted coordinates.

So you could aim earlier and use this as a base for your auto speed.

But remember, too much prediction makes people think that you use “AutoWall”.



bool bSoonvisible(int iIndex)

{

float to[3], lastpred = cvar.predahead;

cvar.predahead = cvar.vpreahead;// apply some leeb value here :)

PredictTarget(iIndex,(float*)to);

cvar.predahead = lastpred;

pmtrace_t tr;

gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );

gEngfuncs.pEventAPI->EV_PlayerTrace( me.pmEyePos, to, PM_WORLD_ONLY, me.ent->index, &tr );

return ( tr.fraction == 1.0 );

}









no Flash



241CF178 DFE0 FSTSW AX

241CF17A F6C4 05 TEST AH,5

241CF17D 0F8B 45040000 JPO client.241CF5C8 // k

241CF183 8B0D D4304124 MOV ECX,DWORD PTR DS:[244130D4] ; material.0DA85460

241CF189 8B11 MOV EDX,DWORD PTR DS:[ECX]

241CF18B 57 PUSH EDI

241CF18C 6A 00 PUSH 0

241CF18E 6A 01 PUSH 1

241CF190 68 3C8B2F24 PUSH client.242F8B3C ; ASCII "ClientEffect

textures"

241CF195 68 CC803324 PUSH client.243380CC ; ASCII "effects/flashbang"



Radar



241FD3E6 84C0 TEST AL,AL

241FD3E8 74 4C JE SHORT client.241FD436 // k

241FD3EA 8D5F FF LEA EBX,DWORD PTR DS:[EDI-1]

241FD3ED 53 PUSH EBX

241FD3EE 8BCE MOV ECX,ESI









simple zoom



240E8C30 8A81 E0000000 MOV AL,BYTE PTR DS:[ECX+E0] ; bool

CInput::CAM_IsOrthographic(void) // should return true for zoom

240E8C36 C3 RETN

Sniper crosshair

Radar



a simple & small radar patch , it shows the enemys / teammates or all players.



241C5E40 FF50 34 CALL DWORD PTR DS:[EAX+34]

241C5E43 3B4424 14 CMP EAX,DWORD PTR SS:[ESP+14]

241C5E47 75 0A JNZ SHORT client.241C5E53 // jne -> only team / je ->

only enemys

241C5E49 56 PUSH ESI

241C5E4A 57 PUSH EDI

241C5E4B 8D4B EC LEA ECX,DWORD PTR DS:[EBX-14]

241C5E4E E8 EDF9FFFF CALL client.241C5840

241C5E53 83C7 01 ADD EDI,1

241C5E56 83FF 40 CMP EDI,40

241C5E59 ^7E AF JLE SHORT client.241C5E0A



Related docs
Other docs by Kerala g
union-budget-2012-13-highlights
Views: 89  |  Downloads: 0
notification M.Tech_05-03-09
Views: 58  |  Downloads: 0
India_Customs Regulation 1
Views: 55  |  Downloads: 0
CE Notification 39-2011-12.9.2011
Views: 53  |  Downloads: 0
STATISTICS
Views: 71  |  Downloads: 0
A Hero (R.K. Narayan)
Views: 88  |  Downloads: 6
RRBPatna-Info-HN
Views: 100  |  Downloads: 0
RRB-Notice-Para
Views: 102  |  Downloads: 0
By registering with docstoc.com you agree to our
privacy policy

You are almost ready to download!

You are almost ready to download!