Forcing Socket Bind in C# [Code Injection & Shell Extension]

Published on Friday, 15 April 2016 08:22

Having access to multiple internet connections at home, I found it hard to balance the usage in Windows especially when I want to download multiple files through them.

The thing is that in Windows OS you can't in any way force a program to use a specific network interface by modifying the routing table nor you have open access to other parts of the system to create a special scenario for your process.

Fortunately, tho, each program initializing a socket connection can bind the newly created socket to a specific network interface if they desire to. The problem is that with the increasing number of frameworks and interest for using higher level programming languages, most of the programmers are not aware of that or simply don't care much to put a setting in their application for this. In my case, for example, I really hoped that uTorrent and Internet Download Manager had this option.

As there is no other way to force bind a program to a network interface except what described earlier, the only way to get the desired outcome is to find a way to forge a request for this binding using the main program's process. But to do so, we first need to somehow put our code inside an already compiled and executing the program in the memory.

Injecting a code inside another program and listening for different calls of Windows API in it, is called Code Injection and API Hooking. Windows' C++ developers are no stranger to these techniques; in-fact they used to do so a lot in old days. Yet currently this method is not very popular as new technologies got so far from the machine code that they can't be injected inside the memory of another program easily. And you know, everything is in the cloud now times; so why even bother with Windows programming?

Anyway, I found a program tat does exactly that, named ForceBindIP, a fine piece of code actually. Unfortunately, I had some problems with it:

1st, I had no idea which program uses which network interface after running the program with ForceBindIP. No indication, at all.

2nd, ForceBindIP couldn't handle connections made with WSAConnect function.

3rd, It was hard to run a program with ForceBindIP in everyday usage. Especially when IP address of the network adapter was dynamic.

4th, ForceBindIP couldn't detect when IP of the network interface changes. In fact, it seems that it also does ignore the return value of bind call resulting in not applying the change to some connections if bind fails. Which mean you may end up using the main internet connection if something happens with the selected network adapter making the bind requests to fail.

So the only other way around it was to rewrite the program. But then I wanted to do something new and I wasn't really in the mood for writing C++. So I tried to do it using C# and dot-Net.

There is a library named EasyHook which I had some experience with a couple of years back after Detours died. It was so buggy and crashy back then, but I thought I have to give it another shot. Other than the possibility to write the code in C# and having access to all those shiny libraries that comes with .Net Framework, EasyHook saves you from a lot of troubles with its methods and helper classes to inject your code, hook the functions, inter-process communication (IPC), multithreading and stability of host program (if you do your part correct). And with .Net 4 being around for some years now, you could hook any managed and un-managed program from one library compiled for both x86 and x64 architects (AnyCPU). In fact, you can even incorporate the injected library with the injector itself resulting in one executable file as for everything. Until .Net 4, it wasn't possible to inject the code into some managed programs due to the impossibility of loading of different versions of run-time by one process. But that's the old story now.

Using EasyHook is relatively easy. For injecting your code into the program, all you have to do is simply using RemoteHooking.Inject method. There is another method called RemoteHooking.CreateAndInject but I found it somehow useless as it couldn't inject the code inside managed code due to run-time stealing the first thread from EasyHook. So you better run the program yourself and then use the Process.Id of the program to inject the code. You may loose some of the first connections, but nothing to worry about too much.

processId = Process.Start(CommandLineOptions.Default.Execute, CommandLineOptions.Default.Arguments)?.Id ?? 0;
. . . . . .
RemoteHooking.Inject(processId, injectorAddress, injectorAddress, networkId, injectorAddress, CommandLineOptions.Default.Delay, CommandLineOptions.Default.Debug);


Using EasyHook you can easily send your desired arguments to the injected code. For example, in the above sample, I sent the selected networkId and some other options to the injected code.

This is all you need to do for injecting your code inside the program; now you need to write the injected code. To do so you simply need to create a class implementing the IEntryPoint interface. EasyHook uses that class automatically after injecting the code.

public class Guest : IEntryPoint
    {

Two key parts of this class are the constructor and the Run method. Both accepting all arguments sent to them with Run method being in charge of hooking the functions and keeping the injected thread alive.

To hook a function you need to know exactly where it is located and the exact name of it, including all the affixes. You also need to indicate which thread you want to accept calls from. Here is the method I wrote for adding a new hook:

private void AddHook(string libName, string entryPoint, Delegate inNewProc)
{
    try
    {
        var localHook = LocalHook.Create(LocalHook.GetProcAddress(libName, entryPoint), inNewProc, null);
        // Exclude current thread (EasyHook)
        localHook.ThreadACL.SetExclusiveACL(new[] { 0 });
        lock (_hooks)
            _hooks.Add(localHook);
        DebugMessage(entryPoint + "@" + libName + " Hooked Successfully");
    }
    catch (Exception e)
    {
        DebugMessage("Failed to Hook " + entryPoint + "@" + libName);
        DebugMessage(e.ToString());
    }
}

This will create a hook and assigns a callback to it. Then it will set an excluding rule for threads indicating that the hook should not capture the calls from the current thread. To do so we used an integer array with one element, being 0, means current thread for the LocalHook.ThreadACL.SetExclusiveACL method. Please note that the current thread, if executed from the Run method, is the EasyHook's thread, executing OUR code. So yeah, we don't really want to (re)capture our calls.

I also found that in some rare cases, we may end up hooking a function before the main program even loads the library containing it, making the hook registration impossible. You can't take a fish if there is no water in the lake. In that case, we can load the library our-self.

But LoadLibrary is tricky; the thing is that the second call to the LoadLibrary returns null. So if we load the library before the main executable, we may end up with undefined consequences as the main program tries to load the library after that. Fortunately, tho, it seems that a registered hook still works if you unload the library and load it again. So I wrote another piece of code to do so. Load the desired library, hook the functions and then unload the library if only we were the first one who did load it.

But then, there should be some sort of race condition here between our code and the main program. What if we load the library first, but while hooking the functions, the main program tries to load it again and ends up with a null handler? What if we unload the library while the main program still expects it to be there. But that didn't happen to my code yet. So I think you need to choose between bad or worse sometimes. The only other way that I can think of to solve this problem is to hook the LoadLibrary function.

Anyway, here is the method we currently use:

private void LoadLibrary(string libraryName, Action code)
{
    // Forcing the hook by pre-loading the desired library
    var library = Library.LoadLibrary(libraryName);
    code();
    // Unload the library if only we were the ones loading it for the first time
    if (!library.Equals(IntPtr.Zero))
    {
        Library.FreeLibrary(library);
    }
}


Now, let's take a look at the Run method:

LoadLibrary(@"ws2_32.dll", () =>
{
    AddHook(@"ws2_32.dll", "connect", new Delegates.ConnectDelegate(Do_Connect));
    AddHook(@"ws2_32.dll", "WSAConnect", new Delegates.WsaConnectDelegate(Do_WsaConnect));
    AddHook(@"ws2_32.dll", "bind", new Delegates.BindDelegate(Do_Bind));
});

AddHook(@"kernel32.dll", "CreateProcessW",
    new Delegates.CreateProcessDelegate(
        (IntPtr lpApplicationName, IntPtr lpCommandLine, IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,
            IntPtr lpCurrentDirectory, IntPtr lpStartupInfo, out ProcessInformation lpProcessInformation) =>
            Do_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
                bInheritHandles, dwCreationFlags, lpEnvironment,
                lpCurrentDirectory, lpStartupInfo, out lpProcessInformation, true)));
AddHook(@"kernel32.dll", "CreateProcessA",
    new Delegates.CreateProcessDelegate(
        (IntPtr lpApplicationName, IntPtr lpCommandLine, IntPtr lpProcessAttributes,
            IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,
            IntPtr lpCurrentDirectory, IntPtr lpStartupInfo, out ProcessInformation lpProcessInformation) =>
            Do_CreateProcess(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
                bInheritHandles, dwCreationFlags, lpEnvironment,
                lpCurrentDirectory, lpStartupInfo, out lpProcessInformation, false)));

// Ansi version of the SetWindowText function
AddHook(@"user32.dll", "SetWindowTextA",
    new Delegates.SetWindowTextDelegate((handle, text) => Do_SetWindowText(handle, text, false)));

// Unicode (Wide) version of the SetWindowText function
AddHook(@"user32.dll", "SetWindowTextW",
    new Delegates.SetWindowTextDelegate((handle, text) => Do_SetWindowText(handle, text, true)));


As you can see in the above piece of code, we hooked connect, WSAConnect and bind functions from the wsa2_32 library for the purpose of detecting new connections and manual binds. We did also hook the CreateProcessW and CreateProcessA functions from the kernal32 library to detect new child processes and inject our little code into them as well.

For the sake of user experience, we did hook the SetWindowTextA and SetWindowTextW functions from the user32 library so we can detect any changes in the title bar of the application and show the selected network interface for the current process.

Another good thing about EasyHook (C# actually) is that you can use anonymous methods, so I used one function to handle both ANSI and WideWord (Unicode) version of hooked functions. Now, isn't it beautiful?

Let's see what we did in the connect callback:

private SocketError Do_Connect(IntPtr socket, ref SocketAddressIn address, int addressSize)
{
    if (!BindSocket(socket, address.Family, address.IPAddress.IpAddress))
    {
        DebugMessage(Socket.WSAGetLastError().ToString());
        return SocketError.SocketError;
    }

    var returnValue = Socket.Connect(socket, ref address, addressSize);

    if (returnValue == SocketError.SocketError && Socket.WSAGetLastError() == SocketError.Success)
    {
        returnValue = SocketError.Success;
    }

    return returnValue;
}


While in the body of this method, we are sure that there was a call for connecting to a remote (or local) address; so we should bind it to the network interface we want, then if binding goes well we will ask for the actual connect function from ws2_32 library to do the rest.

It seems that sometimes, the return value of connect function indicates a failure while the last error of the WinSock shows a success. In that case, the host program may get confused; so I found the best way to avoid this is to modify the return value of the callback to success. But then I am not sure why this only happens when my code is in place.ace.

[DllImport("ws2_32", SetLastError = true, EntryPoint = "connect")]
public static extern SocketError Connect(IntPtr socket, ref SocketAddressIn address, int addressSize);


Now let's take a look at the Bind method we called from the Do_Connect method:

private bool BindSocket(IntPtr socket, AddressFamily addressFamily, IPAddress ipAddress, int portNumber = 0)
{
    switch (addressFamily)
    {
        case AddressFamily.InterNetwork:
            if (ipAddress.Equals(IPAddress.Any))
            {
                return true;
            }
            if (IsIpInRange(ipAddress, IPAddress.Parse("127.0.0.0"), IPAddress.Parse("127.255.255.255")))
            {
                return true; // Loopback
            }
            if (IsIpInRange(ipAddress, IPAddress.Parse("10.0.0.0"), IPAddress.Parse("10.255.255.255")))
            {
                return true; // Private Network
            }
            if (IsIpInRange(ipAddress, IPAddress.Parse("172.16.0.0"), IPAddress.Parse("172.31.255.255")))
            {
                return true; // Private Network
            }
            if (IsIpInRange(ipAddress, IPAddress.Parse("192.168.0.0"), IPAddress.Parse("192.168.255.255")))
            {
                return true; // Private Network
            }
            if (IsIpInRange(ipAddress, IPAddress.Parse("224.0.0.0"), IPAddress.Parse("239.255.255.255")))
            {
                return true; // Multicast
            }
            var networkIp = GetNetworkInterfaceIPAddress(addressFamily);
            if (networkIp == null)
            {
                return false;
            }
            if (networkIp.Equals(ipAddress))
            {
                return true;
            }
            var bindIn = new SocketAddressIn
            {
                IPAddress = new SocketAddressIn.AddressIn { IpAddress = networkIp },
                Family = networkIp.AddressFamily,
                Port = portNumber
            };
            var addressIn = bindIn;
            ContinueExecution(() => DebugMessage("Auto Bind: " + addressIn.IPAddress.IpAddress));
            return Socket.Bind(socket, ref bindIn, Marshal.SizeOf(bindIn)) == SocketError.Success;
        default:
            return true;
    }
}


As we do only support IPv4 in the current version of the code, we ignore the binding part for all other connection addresses, including IPv6. But even then, we do ignore the binding for all local addresses as well as all known private IP spaces. We do also ignore the binding for the reserved multicast IP space. But if the request was for other destinations, then we do try to bind the socket using the bind function of the wsa2_32 library.

[DllImport("ws2_32", SetLastError = true, EntryPoint = "bind")]
public static extern SocketError Bind(IntPtr socket, ref SocketAddressIn address, int addressSize);


This is actually all you need to do to hook the connect function of WinSock and bind it before actually requesting a connection. But I did hook the WSAConnect as well as bind function to be able to capture all connection requests and even bind the listening sockets as well as forcing programs that are aware of binding.

Now our program is complete. But how should the user, use our program?

We can go the same way ForceBindIP has been gone and let the user pass the network interface identification as well as the program address to our application. But that's hard for average users. So we should find an easier way.

Well, I do like the idea of Shell Extensions. A nice drop down menu incorporated into the Windows Explorer and Windows Desktop to let the user selects which network interface a program should use. The idea behind Shell Extensions is very similar to the Injection and Hooking. But in this case, you don't actually need to force feed your code into the program. All you need to do is to provide your code as a COM Server and then the Explorer itself is in charge of loading your code and executing it. You don't actually hook any functions, but you are still inside the main process; hence the name, In-Process Extension.

Writing an In-Process Shell Extension using C# is not actually recommended. Apart from the problems that we had with classic scenario of Injecting a piece of code, you may end up with serious performance downgrades too. But since our code is very simple and Explorer's processes are very few at any given time (usually less than 3 active Explorer process), I found it accepting to use the C# for writing such an extension. Personally. Still, the performance hit is noticeable, but only the first time you open the Context Menu in an Explorer process. It seems that the performance hit is the result of loading .Net run-time; as it won't happen again until you restart the Explorer process.

SharpShell is a great library out there for writing these extensions. In fact, you write a lot less code using SharpShell than you had to write with C++. And again, unlike C++ you don't need to compile the library two times for x86 and x64 compatibility. Let's take a look at the whole code of our shell extension:

[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, @".exe")]
internal class DynamicMenuExtension : SharpContextMenu
{
    protected override bool CanShowMenu()
    {
        // Only show the menu when application is installed, there is just one executable
        // file selected and some network interface to select from
        return !string.IsNullOrWhiteSpace(GetNetworkAdapterSelectorAddress()) &&
                SelectedItemPaths.Count() == 1 &&
                NetworkInterface.GetAllNetworkInterfaces()
                    .Any(
                        networkInterface =>
                            networkInterface.SupportsMulticast &&
                            networkInterface.OperationalStatus == OperationalStatus.Up) &&
                Path.GetExtension(SelectedItemPaths.First())?.ToLower() == ".exe";
    }

    protected override ContextMenuStrip CreateMenu()
    {
        var explorerMenu = new ContextMenuStrip();
        var extensionMenu = new ToolStripMenuItem(Resources.DynamicMenuExtension_CreateMenu_Bind_to, Resources.x16);
        var i = 0;
        // Going through all network interfaces and add them to the list
        foreach (
            var networkInterface in
                NetworkInterface.GetAllNetworkInterfaces()
                    .Where(
                        networkInterface =>
                            networkInterface.SupportsMulticast &&
                            networkInterface.OperationalStatus == OperationalStatus.Up))
        {
            // Copying the network id to a variable
            var networkId = networkInterface.Id;
            // Add normal execution item
            extensionMenu.DropDownItems.Insert(i, new ToolStripMenuItem(networkInterface.Name, null,
                (sender, args) => BindTo(networkId, false)));
            // Add separator, only once
            if (i == 0)
                extensionMenu.DropDownItems.Add(new ToolStripSeparator());
            i++;
            // Add run as administrator execution item
            extensionMenu.DropDownItems.Add(
                new ToolStripMenuItem(
                    string.Format(Resources.DynamicMenuExtension_CreateMenu_Run_as, networkInterface.Name), null,
                    (sender, args) => BindTo(networkId, true)));
        }
        explorerMenu.Items.Add(extensionMenu);
        return explorerMenu;
    }

    private void BindTo(string networkInterfaceId, bool asAdmin)
    {
        try
        {
            var executableAddress = GetNetworkAdapterSelectorAddress();
            if (string.IsNullOrWhiteSpace(executableAddress))
            {
                return;
            }
            // Executing the "NetworkAdapterSelector.Hook" and passing the address of executable file.
            var processInfo = new ProcessStartInfo(executableAddress,
                $"-n \"{networkInterfaceId}\" -e \"{SelectedItemPaths.First()}\"")
            {
                WindowStyle = ProcessWindowStyle.Hidden,
                CreateNoWindow = true,
                UseShellExecute = true
            };
            if (asAdmin)
            {
                // Forcing administrator privileges
                processInfo.Verb = @"runas";
            }
            Process.Start(processInfo);
        }
        catch (Exception e)
        {
            // Check if operation canceled by user
            if ((e as Win32Exception)?.NativeErrorCode == 1223)
            {
                return;
            }
            // Otherwise, show an error message to the user
            MessageBox.Show(e.ToString(), Resources.DynamicMenuExtension_BindTo_Network_Adapter_Selector,
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}


By inheriting the SharpContextMenu class, you have access to the methods that Explorer calls when it expect an answer. In our case, only two methods are important, CanShowMenu and CreateMenu; and as you can clearly see, it is unbelievably easy to modify the context menu of the Explorer.

Please note that in the above example we did register our extension to be used only with files registered under the executable class. Limiting the times our code will be executed.

Simple as that, we have written a nice Windows Explorer Shell Extension in pure C#.

Now if you are interested in the source code or the program itself, check the project's github page.

Read More

فیلترینگ هوشمند، توضیحات فنی و چالش های پیش رو

Published on Monday, 17 November 2014 14:49

همراه با سیاست های اخذ شده توسط وزارت ارتباطات جمهوری اسلامی ایران در رابطه با فیلترینگ و دنبال کردن موضوع جذاب فیلترینگ هوشمند توسط اقشار مختلف جامعه مخصوصا قشر جوان و دانشگاهی کشور که از اصلی ترین کاربران اینترنت و همچنین شبکه های اجتماعی میباشند، این سوال مطرح میشود که موضوع فوق الذکر، در درجه اول تا چه مقدار قابل اجرا و عملی است؟ سوالی که شاید تا به امروز کمتر از دید فنی به آن توجه شده باشد.

 

تلاش این نوشته، بررسی فنی موضوع فیلترینگ هوشمند وب سایت ها و سرویس ها، مشخص کردن موانع فنی، پیشنهاد راه حل و در انتها بررسی کارایی سیستم است.

 

Read More

Aptana and Git through SSH, the big problem

Published on Monday, 18 November 2013 12:01

We all know that despite the fact that Aptana is one of the best Eclipse based IDEs out there, it has lot of bugs. Part of these bugs are because of multi-platform nature of this application and most of them are not very annoying, but this one.

If you try to use Aptana with Git (over SSH) using "Keys" for authentication, you usually receive an authentication fail error (^). Which is clearly some sort of bug because Aptana supposed to be more integrated with Git and show us at least some sort of dialog box for selecting a "Key" file.

Read More

OpenNI 2

Published on Thursday, 28 February 2013 01:44

I am old fan of OpenNI when there was no other readable frame work for using Kinect, and when OpenNI 2 released I was shocked by its nice new design and architect so I decided to give it a try as soon as I can. Fortunately I had access to it even more than two months before its public launch (thanks to PrimeSense for their trust) but first time I tried it seriously was with public release of OpenNI 2.

 

First thing I found very annoying was lake of .Net Wrapper so I wrote one my self named NiWrapper.Net to solve this problem. Then I tried to port my old 3D Photo Capture app using NiWrapper to OpenNI 2 and it was successful, you can download it from here. But now at last step I re-wrote my old Kinect Virtual Camera this time with OpenNI 2 Virtual Webcam name (aka NiVirtualCam). NiVirtualCam is actually a DirectShow filter and a C# server app that stream and send data to DirectShow filter. This way is very affective for streaming data to more than one application after new changes in OpenNI architect in version 2 which limits using of a device from multiple applications.

 

Read More

Reading name and location of icons in Desktop using C#

Published on Tuesday, 19 February 2013 23:01

Last week, one of my friends asked me about a way to retrieve list of desktop icons and their location on the screen. But is it even possible to get the list of Icons (not "Files") and also their location on the "Screen"?

Actually Desktop is an application or more clearly, one instance of Explorer.exe; and it is basically a big ListView. So we can access its items and other properties using List View Messages and SendMessage function from user32.dll. A C++ programer could say that this is very easy task to do,

But there are number of problems for writing the same code in C#; first, you need to do a lot of P/Invoke calls, Second, as you need to access the ListView from another process (for example writing an application to show items of desktop which is under Explorer.exe process) any calls to SendMessage method with a Pointer or Object result, gives you an invalid one. The reason of this is because all handles are relative to program position in memory and its different with your application location in memory.

There are number of ways to solve this problem and read other application's memory; One of the ways is to creating a remote thread under that program using CreateRemoteThread and run our code there; Another approach is to create a Hook using EasyHook or similar frameworks and inject it to the victim application; But the easier way is to read the program's virtual space using OpenProcess, WriteProcessMemory and ReadProcessMemory functions from kernal32.dll directly from our application.

Unfortunately there was no working example in C# after hours of Googling. So I started to write my own code and send it to my friend, then sharing it here.

Attached is a class and a sample for above case. It can find ListViews in any process you choose and then it will try to extract item's location and name in that ListView. For example sample application shows icons and their locations at desktop.

 

Read More

NiWrapper: OpenNI 2 .Net Wrapper

Published on Friday, 15 February 2013 21:44

Hi everybody,

 

Today I am going to show my work in last three days to public. NiWrapper.Net, a OpenNI 2 .Net Wrapper


Lack of a .Net wrapper for OpenNI 2 showed it-self to me when I tried to port my old "3D Photo Capturing Tool" to OpenNI 2 and there was no way to do this; this and the fact that PrimeSense has no plan to write one (as one of their developers told me that they have no time for this wrapper in near future) forced me to write my own wrapper; Now after three days, here I am sharing it with you, .Net developers.

Just like my other projects, it is a open source too project and as result it is available in GitHub at the below address:

https://github.com/falahati/NiWrapper.Net

There are compiled packages for both x86 and x64 versions of OpenNI along with OpenNI redist files in "Package" directory of the same repository. These packages compiled for .Net framework 4 Client Profile but you can compile this project your-self with .Net 2 and and later version of framework. Steps you need to take to use this project is to add NiWrapper.Net.dll to your project references and copy other files to project executable directory. Everything in under OpenNIWrapper name space.

https://github.com/falahati/NiWrapper.Net/tree/master/Packages

 

There are number of examples in the solution as well as support for NiTE2. And best of all, you can simply use NuGet packages:

http://www.nuget.org/profiles/Falahati

As a side note, please don't forget to use "using" and "dispose" for objects in your app. Also always put a OpenNI.Shutdown() at end of your code. These will clean memory and release resources.

Any way, :)

Read More

KinectDevs.com Redirect Page

Published on Friday, 19 October 2012 23:20

Hi,

 

If you are visiting this page so you tried to open KinectDevs.com. Actually KinectDevs.com is closed and no longer available because of huge amount of spammers. I moved all projects and posts to here. Search below list for desired information:

 

How to download and install OpenNI 2 Virtual Webcam (New version of old Kinect Virtual Camera), (Click here) - New

Newer version of old Kinect Virtual Camera. It now use OpenNI 2 and support all OpenNI compatible devices including Kinect, and many more fixed problems. Install this application to use your Kinect / Asus Xtion / Primesense Sensor as webcam; post your question, opinions, etc there.

 

How to download and install OpenNI 2 3D Photo Capture Tool, (Click here) - New

Newer version of old Kinect 3D Photo Capture Tool application. It now use OpenNI 2 and support all OpenNI compatible devices including Kinect. This application will try to capture 3D photos using your OpenNI compatible device; post your question, opinions, etc there.

 

How to download and install Kinect Error Reporting Tool, (Click Here) - Obsolete

An application to solve common problems with OpenNI 1.0.0.23 and NITE 1.3.0.18 (Old versions); post your question, opinions, etc there. IF YOU WANT TO POST YOUR LOG FILE PLEASE POST IT IN THE APPLICATION's PAGE, NOT HERE.

 

How to download and install OpenNI 1.0.0.23, (Click here) - Obsolete

Step by step instructions of installing OpenNI 1.0.0.23 and Avin's Kinect Sensor driver; post your question, opinions, etc there.

 

How to download and install NITE 1.3.0.18, (Click Here) - Obsolete

Step by step instructions of installing NITE 1.3.0.18; post your question, opinions, etc there.

 

 

Any other question, do you need any other information?! Ask me below:

Read More

Site is UP (At last)

Published on Friday, 19 October 2012 22:53

Hi there,

 

Actually after lot of delays, at least I found some free time to finish my personal website. I know it is not that much good specially design; it is because I am not a designer, I am only a developer (thinking about percentages that other designers and developers put on their sites and I can say that I am 101% Developer and -1% Designer!).

 

Any way this is my new web site. Don't be shy and tell me your opinions about my website and its problems.

 

Also, I am going to close "Kinect Devs" (Actually because of huge amount of spammers), etc and I will move needed files and information to my project page of this new website. You can access to "My Projects" section by clicking here.

 

Thanks for visiting,

- Soroush Falahati

Read More