Solved

Intercept Windows API Calls

Posted on 1998-08-06
52
2,377 Views
Last Modified: 2013-12-03
I want to intercept an API function call.  I am writing a TCP/IP tunneling program and need to intercept all calls to winsock32.dll and then make those calls from with in my program.  I do not want to use any 3d party utilities (like SoftICE) or replace the winsock32.dll.  So how do I do this programmically?  What can I do in C/C++ or ASM to intercept these or any other API calls before windows calls the code in the approiate DLL?
I remember using a program called AutoSOCKS that captured the TCP/IP information and automatically entered necessary proxy information so it appeared that your system was directly connected to the internet.  They did not replace the winsock32.dll file to do this either.  
If needed, I will add more points to the question.
0
Comment
Question by:lordx
  • 21
  • 8
  • 8
  • +4
52 Comments
 
LVL 2

Expert Comment

by:duneram
Comment Utility
Yes this is possible, but you are going to have to put your replacement API's in a DLL and then inject that DLL into any application that uses those apis.  Do you know which application uses the API's that you want to hook?

The reason I ask this is when a 32 bit program starts up, there is a giant table of imported api's that gets resolved.  Up successful loading of the table, you will have a function address for each api.  The trick is to have your DLL install itself in the target application, then replace the api function address in the table with the address of your replacement api (do this for each of them).  Then in your function you need to make (if you want to perform the real api function) the api call the original function address that you replaced.

Its kinda like this:
(example  these addresses are arbritary (not real))

API Jump table
SetForegroundWindow      0x000f0100  
.

Your dll gets mapped into the target process.  You want to hook the SFW api so you locate the function address in the table and replace it with the address of your function

MySetForegroundWindow starts at 0x07000300 (in this example)

API Jump table
SetForegroundWindow    0x07000300   (my address)

Now whenever the SFW api is called in that app, it will reference the jump table and call yours (in your dll).  You need to make sure you eventually invoke the original address of 0x000f0100 so that the original SFW is called.

I will post an answer in code in a few moments.
0
 
LVL 2

Expert Comment

by:duneram
Comment Utility
I've done this before and have my own homemade CD's with the code somewhere to do it.  I haven't found the CD yet, but I'll keep looking.  (i have hundreds of homemade cd's....)
0
 
LVL 23

Expert Comment

by:chensu
Comment Utility
0
 

Author Comment

by:lordx
Comment Utility
The winsock spy program is good but it requires me to replace the winsock32.dll.  This is something I did not want to do.  Duneram's idea is what I am looking for.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Duneram's idea seems to be good, but (even if it really works :-) you would have do manipulate all applications you want to hook.
On "www.sysinternals.com" there is a sample named "regMonitor" (for Win95 and WinNT). This sample hooks system wide (!) all calls for registry. Perhaps you could hook winsock calls in the same way. (I'm not sure, it's only an idea.)
But then you would have to write drivers! :-(
0
 
LVL 2

Expert Comment

by:duneram
Comment Utility
I've done the api hook thing and when I get home I'll take a look again for my source
0
 

Author Comment

by:lordx
Comment Utility
Adjusted points to 750
0
 
LVL 3

Accepted Solution

by:
xyu earned 1000 total points
Comment Utility
Here is exact answer for Your request...
The ZIP file with entire project I've put at: "http://www.geocities.com/SiliconValley/1741/miscprog/intercept.zip"

The listing is :

/****************************************************************************/
/** intercept.cpp                                                          **/
/** ---------------------------------------------------------------------- **/
/** Example of interception of an API or any DLL function call             **/
/** ---------------------------------------------------------------------- **/
/** The method shown here may be very impressive in conjunction with       **/
/** CreateRemoteThread API                                                 **/
/** ---------------------------------------------------------------------- **/
/** July 23, 1998 by Oleg Kagan                                            **/
/****************************************************************************/

/****************************************************************************/

//============================================================================
#include <windows.h>

// Switch all optimizations off
// (Visual C specific... For any other compiler do the same thing)
//============================================================================
#pragma optimize("", off)

//============================================================================
#define MakePtr(Type, Base, Offset) ((Type)(DWORD(Base) + (DWORD)(Offset)))

//============================================================================
BOOL InterceptDllCall(

      HMODULE hLocalModule,
      const char* c_szDllName,
      const char* c_szApiName,
      PVOID pApiNew,
      PVOID* p_pApiOrg,
      PVOID pApiToChange
      
){
    PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)hLocalModule;
    PIMAGE_NT_HEADERS pNTHeader;
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc;
    DWORD dwProtect;
      BOOL bSuccess = FALSE;
   
    DWORD dwAddressToIntercept;

      if (pApiToChange) {
            dwAddressToIntercept = (DWORD)pApiToChange;
      }
      else {
            dwAddressToIntercept = (DWORD)GetProcAddress(
                  GetModuleHandle((char*)c_szDllName), (char*)c_szApiName
            ) /*GetProcAddress*/;
      } /*iff*/;

    if (IsBadReadPtr(hLocalModule, sizeof(PIMAGE_NT_HEADERS)))
        return FALSE;
   
    if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
        return FALSE;
   
    pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
    if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
        return FALSE;
   
    pImportDesc = MakePtr(
            PIMAGE_IMPORT_DESCRIPTOR, hLocalModule,
        pNTHeader->OptionalHeader.DataDirectory[
                  IMAGE_DIRECTORY_ENTRY_IMPORT
            ] /*pNTHeader->OptionalHeader.DataDirectory*/.VirtualAddress
      ) /*MakePtr*/;
   
    if (pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeader) return FALSE;
   
      while (pImportDesc->Name) {
            PIMAGE_THUNK_DATA pThunk;
   
            pThunk = MakePtr(
                  PIMAGE_THUNK_DATA, hLocalModule, pImportDesc->FirstThunk
            ) /*MakePtr*/;
   
            while (pThunk->u1.Function) {
                  if (DWORD(pThunk->u1.Function) == dwAddressToIntercept) {      
                        if (
                              !IsBadWritePtr(
                                    (LPVOID)pThunk->u1.Function, sizeof(DWORD)
                              ) /*!IsBadWritePtr*/
                        ){
                              if (p_pApiOrg)
                                    *p_pApiOrg = PVOID(pThunk->u1.Function);
                              (PDWORD)pThunk->u1.Function = (PDWORD)pApiNew;
                              bSuccess = TRUE;
                        }
                        else {
                              if (
                                    VirtualProtect(
                                          (LPVOID)(&pThunk->u1.Function), sizeof(DWORD),
                                          PAGE_EXECUTE_READWRITE, &dwProtect
                                    ) /*VirtualProtect*/
                              ){
                                    DWORD dwNewProtect;

                                    if (p_pApiOrg)
                                          *p_pApiOrg = PVOID(pThunk->u1.Function);
                                    pThunk->u1.Function = (PDWORD)pApiNew;
                                    bSuccess = TRUE;

                                    dwNewProtect = dwProtect;
                                    VirtualProtect(
                                          (LPVOID)(&pThunk->u1.Function), sizeof(DWORD),
                                          dwNewProtect, &dwProtect
                                    ) /*VirtualProtect*/;
                              } /*if*/
                        } /*iff*/
                  } /*if*/
                  pThunk++;
            } /*while*/
            pImportDesc++;
      } /*while*/

    return bSuccess;
} /*InterceptDllCall(HMODULE, const char*, const char*, PVOID,PVOID*,PVOID)*/

//============================================================================
void ChangeText(

      char* szText
      
){
      size_t nLength = strlen(szText);
      for (size_t i = 0; i < nLength; ++i) {
            szText[i] = char((i % 2) ? tolower(szText[i]) : toupper(szText[i]));
      } /*for (size_t i)*/
} /*ChangeText(char*)*/

//============================================================================
typedef int (*TMessageBoxFuncPtr)(HWND, LPCTSTR, LPCTSTR, UINT);
TMessageBoxFuncPtr p_fnMessageBoxOrg = NULL;

//============================================================================
int WINAPI MyMessageBox(

      HWND hWnd,          // handle of owner window
      LPCTSTR lpText,     // address of text in message box
      LPCTSTR lpCaption,  // address of title of message box
      UINT uType          // style of message box

){
      if (!p_fnMessageBoxOrg) return 0;
      ChangeText((char*)lpText); ChangeText((char*)lpCaption);
      int nResult = (*p_fnMessageBoxOrg)(hWnd, lpText, lpCaption, uType);
      return nResult;
} /*MyMessageBox(HWND, LPCTSTR, LPCTSTR, UINT)*/

//============================================================================
extern "C" int WINAPI WinMain(

      HINSTANCE hInstance,  // handle to current instance
      HINSTANCE /*hPrevInstance*/,  // handle to previous instance
      LPSTR szCmdLine,  // pointer to command line
      int /*nCmdShow*/  // show state of window

){
      char* c_szTitle = "API Call Interception";
      UINT uStyle = MB_OK | MB_ICONHAND | MB_SYSTEMMODAL;

      MessageBox(NULL, "Here it is normal                 ", c_szTitle, uStyle);

      // Lets Change it
      //----------------
      InterceptDllCall(
            hInstance, "user32.dll", "MessageBoxA",
            (PVOID)&MyMessageBox, (PVOID*)&p_fnMessageBoxOrg,
            NULL
      ) /*InterceptDllCall*/;

      MessageBox(NULL, "Beware of the mad hackers         ", c_szTitle, uStyle);

      InterceptDllCall(
            hInstance, "user32.dll", "MessageBoxA",
            (PVOID)p_fnMessageBoxOrg, NULL, (PVOID)MyMessageBox
      ) /*InterceptDllCall*/;

      MessageBox(NULL, "Here it is almoust normal again :)", c_szTitle, uStyle);

      return 0;
} /*WinMain(HINSTANCE, HINSTANCE, LPSTR, int)*/


0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
Don't forget to check that DLL is loaded :)
0
 
LVL 2

Expert Comment

by:duneram
Comment Utility
hope that's what your looking for.  I am starting my first vacation in over 2 years...  so I won't be around for about a week.  I never found my source code but I know its on one of my cd's...


0
 

Author Comment

by:lordx
Comment Utility
Your answer is almost exactly what I am looking for.  The code you submitted works great for API functions in DLL's of the current process but not other processes.  I need to intercept the API calls to other processes as well.  The top of the code lising refrences the CreateRemoteThread function which may work for some NT applications.  I need this to work on both NT and 95/98.  For example, if I have a program running that is displaying messageboxes (or calling any other API functions like "socket" or "connect" for winsock functions), I need this program to alter those messageboxes in the other program.  There are some places in the InterceptDllCall function that reference an HMODULE or HINSTANCE object but if I pass the hInstance of another window to the function it fails.


0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
HMODULE or HINSTANCE here is not a window.... it is instance of the DLL (Module) I'm working now on program (NT service) that You will be able to configure to inject any specified DLL in all precesses runninng after the service started... than i You can use the DLL to intercept API calls (unforunately I can't put too much time on it now - I have deadline to release the version at place i'm working...) if You could wait ... in 1-2 weeks i plan to finish that server... if not - i can transfer to You GetAdmin (hehe) sources that doing something similar... and You can try to use it to build server by yourself.. if not to take general case it could be faster :)
0
 
LVL 4

Expert Comment

by:agreen
Comment Utility
xyu: i'm intersting in the GetAdmin sources. Can you send it to green@maxho.com ?
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
agreen:
 Wait for 1-2 weeks i'll release the service i talk about with sources...
0
 
LVL 4

Expert Comment

by:agreen
Comment Utility
xyu:
Ok, I'll be waiting. Please don't forget it and don't leave me with only the thing that your nick means :)
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
agreen: How do You know, what my nick is... (meanwile its a shame, but choose it while i was totally drunk but I don't want to change it  :) )

0
 
LVL 4

Expert Comment

by:agreen
Comment Utility
xyu: :))
So, am I right that your nick came from the russian language ?
Also I think that now you live in Israel and, probably, work at Mercury. This place isn't a chat room, so if you want to know the reasons for such conclusion just mail me. (green@MAXHO.com) :)
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
to lordx: OK... i have very nice dll to inject any custom dll into specified process and that the custom dll can use method described in my answer to intercept any of the API or other DLL calls... it works now under NT4 and it suppose to work under WIN98... so if You need it leave me a comment... so I'll publish it... (it called syringe.dll) Next week I plan to publish "plaguesrv.exe" that will be NT service to perform "global infection" :)
leave comments here to contact me
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

that sounds very interesting...
Would be very kind of you to eMail me your dlls, drivers, sources, or whatever (Mathias.Rauen@gmx.de).    :-)

Thanx a lot, Madshi.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
Madshi... only after 850 points :)
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
Ohhh that's bad!    :-(
I'll think about it...
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
Madshi... Good luck :)
0
 

Author Comment

by:lordx
Comment Utility
Thanks.  I do need it.  Either publish it here or email me at lordx@wam.umd.edu.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lordx: do You want it as is or You can wait ro plaguesrv "Global Infector"? If You want it as is You have just to promise not to publish it until i'll release plaguesrv :) are You agree?
0
 

Author Comment

by:lordx
Comment Utility
How about you send me what you have (source included I hope) so I can start integrating it into my program.  Once I see that it works I will grade the question so you get your points.  When you publish plaquesrv, email me a copy at lordx@wam.umd.edu.  I will not release my program that will use it until after you have published plaquesrv.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lords... i sent it to You alreade 2-3 days ago... How is it going....?
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:lordx
Comment Utility
I am having a problem compiling the code with psapi.lib.  I am using Borland C++ 5.02 and it reports that the file (psapi.lib) has an "invalid OMF record, type 0x21".  The code u provided seems to compile fine, but I can't link samp1.  Since I am not using MS Development Studio (according to the make files you used that) I don't know for sure what format to compile each file to.  Currently I am doing this:
samp1_inj: samp1_inf.dll
syringe: syringe.dll
samp1: samp1.exe
I do realize that you had not completed the project to the point of publication when you sent it to me.  Maby I need to compile psapi.lib under Borland.  I have a version of psapi.cpp from the getadmin program but it didn't compile properly.  Where did u get the psapi.lib file you sent me?
I will try to post a comment later on if I get it working.  Do you have ICQ?  If so it may be easier to do an online chat to discuss the program.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lordx...
You can find psapi.dll at winnt\system32...
Use implib.exe utility from borland C to generate psapi.lib... (the version i sent to You is in VC5 lib format)...
don't forget to disable all optimizations...
Wait a second... i'll generate for You BC5.01 project...



0
 

Author Comment

by:lordx
Comment Utility
Ok, I got it to compile and run.  (I had to use IMPLIB.EXE for Borland to convert psapi.dll
and syringe.dll to an importable library which created a psapi.lib and syringe.lib that I
could use).
How can I see that it is working?

It looks like I should see the "Hacked" messagebox when samp1_inj.dll is started but I don't.

So, I remarked the "ifdef NEVER" and "endif" statements in samp1_inj.cpp and syringe.cpp so it would always display those message boxes.
When I run samp1.exe:
- I get the "Attach" and "Detatch" messageboxs for samp1_inj.dll and syringe.dll linking to
samp1.exe.  
- I get the "Attach" message box for syringe.dll linking to notepad.exe.
- I don't see any changes in notepad.  I did a search in notepad for text that was not in
the window to have it display a search error messagebox, but the text was not modified.
- When I exit notepad I get the "Detatch" message for syringe.dll's link to notepad.exe

So it is attaching the DLL, but maby not running the HackMessageBox entry function that
makes the modifications.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lordx... my ICQ is 6478563 call me now....
and my email is ok@netvision.net.il

0
 

Author Comment

by:lordx
Comment Utility
Thanks for the code.  It worked perfectly once I added the "_" to the HackMessageBox string in the call to InjectModule (in samp1.cpp).
If you could make the neccessary changes for it to work under win98 I would give you another 200 points.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lordx.. i'm working on it ....
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
lordx/xyu, I have download this intercept demo and got it to work in 98. I was curious if any of you have gotten it to work for Winsock functions. I have tried to capture send but nothing yet.
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
Another thing, This API call interception only seems to work locally within the app. Can this be adapted to catch ALL API calls?
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lucidity... yes it can be adapted... and its easy... You just have to get SYRINGE.DLL written by me and use it :)
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
And how shall I go about doing that? Are you willing to give me the source.. actually I don't need the source, just how to implement it, but the source would be nice. We could trade... I have some source for some stuff I think is cool and potentially useful:

RAW TCP/IP send accept....
Hide process from taskmanager....
Transparent windows like Norton Utilities....
Multi-Threaded Web Server....
File Monitor...

Pick one, Anyway, If it works for me I would owe you one, just name it. I need to be able to see and alter calls to winsock, I'm making a free fuzzy logic web page screener so I need to see the html text and what sites they are going to, maybe GetHostByName(). I would of course credit you for the code.

ciao,
Jason
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lucidity: my E-mail is ok@netvision.net.il what about Yours?
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
liquidy@geocities.com
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
you got the right email but I haven't heard anything from you yet.... whats up?

0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

I'm back again...  :-)

I still don't have 850 points. So I tried your little source example, converted it to Delphi and got it to work. Also now I'm able to inject other processes.
But there is one big problem: Your code works only with implicit loaded DLLs. Am I right? Is there a possibility to intercept calls to explicit loaded DLLs/functions, too? Of course I could just overwrite the DLL function with a jump to my function. But then I couldn't call the original function anymore...

Thanx for your answer...

Regards, Madshi.

P.S: You don't have to tell me here and now HOW it works. Of course I would be glad about that. I just want to know IF you know how to get this done. Then I'll post a question with some points (<850).  :-)
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
You can intrecept any API (e.g. DLL calls) there is an extendet sample that allows You to "infect" notepad.exe  :)

0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

if you look at the "Import Table" of "notepad.exe", you'll see that notepad links all the DLLs implicitly. But please look at "Explorer.Exe". There the "Import Table" is empty. So the way your example works it just can't intercept api calls from the explorer. I've tested it. I've injected the explorer with my own little DLL, but your sources just don't find the api calls in the import table. The loops run through without finding something...
But I want to intercept the CopyFile (e.g.) api calls that the explorer does. So - if your extended sample does not use a completely different way of intercepting, it will not work! Or am I wrong?

Regards, Madshi.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
Explorer.exe is not a problem... i'v intercepted MessageBox for test :) the intreception have to be performed for appropriate (or all) module :) it's easy.... more than that i'll release Plague package next month... so You'll be able to use it for free :)
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

that sounds good (especially that word "free" :-))...
Where can I get this Plaque package from? Will it come with sources?

Thank you,
regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

and me again...
Thanx for the tip with the modules. I only looked through the exe's import table. Now I'm scanning through all DLLs, too. And now your loops intercept "CopyFileA" in "Shell32.DLL". But somehow the explorer's copy actions are still not hooked... :-(
So the same question again: What if a process uses LoadLibrary/GetProcAddress directly ("explicit" linking)? Then the jump address is not in the locations you look through! Right?

BTW, in your sources is a little bug! Perhaps you corrected that already, perhaps not - because it has no serious effect. But it's not nice, though.

if ( !IsBadWritePtr( (LPVOID)pThunk->u1.Function, sizeof(DWORD)
) /*!IsBadWritePtr*/ ...

That's wrong! It should be like this:

if ( !IsBadWritePtr( (LPVOID)(&pThunk->u1.Function), sizeof(DWORD)
) /*!IsBadWritePtr*/ ...

Regards, Madshi.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
I'm not sure it is a bug.... otherwise You will not be able to compile it... -> is not defined for void* :)

0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
xyu,

I AM QUITE SURE!  :-)
Nevertheless it works with this bug in most cases, too. This IsBadWritePtr statement tests a wrong pointer and thus returns always that the pointer is bad. If you look at the "dwProcess" value, returned from the VirtualQuery function (if it succeeds), you'll find that you have already read/write access. I moved the second VirtualQuery line directly under the first one. And it all still worked! Please take a closer look at that!

Regards, Madshi.

P.S: I'm not sure about that compiling issue, because I'm using Delphi. But it's clear somehow. You give in the address that is stored in ...u1.Function. But later you don't want to write the the address that is stored in ...u1.Function but you want to write to ...u1.Function itself.
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
ok... it accepted as a bug... sorry

0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
Madshi, meanwile my mail is ok@netvision.net.il :)
See You :)
Good Luck :)
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
I cannot get your syringe demo to work on anything but NT. is this right?
0
 
LVL 3

Expert Comment

by:xyu
Comment Utility
lucidity: yes it's right, because CreateRemoteThread existsonly on NT and Win98, ans VistualAllocEx works only with NT, nut now i'm in process of creating my own AllocRemote that will work on Win98 as well...
0
 
LVL 2

Expert Comment

by:lucidity
Comment Utility
keep me posted, if you get it to work let me know... If you need any help let me know.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now