Go Back   BWHacks > Development > Reverse Engineering > Code Snippets and Tutorials

Code Snippets and Tutorials The place for open source releases, great information, and tutorials written by other members.

Reply
 
LinkBack Thread Tools

Old 06-30-2008, 02:11 AM   #1 (permalink)
Perma
rol 3905h, 8
Senior Member
Administrator

Saint
 
Perma's Avatar
 
Join Date: Jul 2004
Location: Canada
Posts: 5,414
Perma has disabled reputation
Default [StarCraft] Exhale Interface Source (1.15.2)

Here is the source code to my Exhale interface project for StarCraft. Some of it is a little bit messy as I was experimenting with some features, but most of the core functions are pretty slick.

Feel free to use this source in your own projects, giving credit where it's due. Do try to release your work open source - it helps more people learn. If you have questions about the source, post them here or contact me via private message.


Credits
Zephyrix - A great solution to refreshing issues.
PizzaPan - Module hiding function.
Kc - Original drawing function.

And thanks to all of the 1ovely pe0ple that have helped me along the way.
Attached Files
File Type: zip exhale_db4.zip (11.8 KB, 158 views)

Last edited by Perma : 06-30-2008 at 04:06 PM.
Perma 15 0|\|11|\|3 |\|0\/\/   Reply With Quote
Advertisement
 
Advertisement
Advertisement Sponsored links


Old 06-30-2008, 09:57 AM   #2 (permalink)
XeNotRoN

Deviant
 
XeNotRoN's Avatar
 
Join Date: Mar 2006
Location: Hungary - near to the gates of hell
Posts: 45
XeNotRoN is on a distinguished road
Default

Very nice work! Once we had an idea to implement something like this, but we were lazy asses to write code. It will be even better if you make a windowing system similar to that of win32 + a dialog builder (control anchoring to auto layout controls on resize etc...). ;) With windowed mode plugin it could be useful to be able to detach the window from the starcraft main window as a child wnd of the main wnd. I like projects like this so much, so sad that I have zero time to develop game tools.

One thing I noticed in the code is the hidemodule part. You can replace that to this piece of code, which is win9x compatible, not only winnt. Another good practice is loading the dll without LoadLibrary().

VC++6, Iam lazy ass to make the masm version...
hidemodule.c:
Code:
#include <windows.h>
#include <winnt.h>
#include <stdio.h>

    /*
    // No we do some manual exception handling xD
    //
    // Safe functions must call SetupSEH before they put
    // anything to the stack, so the return function must
    // be on top of stack. This func must return by
    // CleanupSEHasm_ret with ReturnCode in eax.
    // If the function causes an exception then it
    // will return automatically with eax==0
    // A function must be __cdecl to use SetupSEH
    // and CleanupSEHasm_ret cause CleanupSEH does
    // not clean parameters from stack, only returns.
    */

    /*
    // Size of stack space required for SEH frame
    // created by SetupSEH.
    */
#define SEH_STACK   (2*4 + 8*4 + 4)

__declspec(naked) void __stdcall SetupSEH (void *ErrorSafeLoc)
{
    __asm
    {
        // Setup SEH frame
        pop     eax     // ret address
        pushad

        // zero eax: return value on exception
        and     dword ptr [esp+1CH], 0

        push    offset seh_handler_func
        push    dword ptr fs:[0]
        mov     dword ptr fs:[0], esp
        jmp     eax

#define EH_NONCONTINUABLE   00000001H
#define EH_UNWINDING        00000002H
#define EH_EXIT_UNWIND      00000004H
#define EH_STACK_INVALID    00000008H
#define EH_NESTED_CALL      00000010H

    seh_handler_func:
        mov     eax, dword ptr [esp+4]
        test    dword ptr [eax+EXCEPTION_RECORD.ExceptionFlags], EH_NONCONTINUABLE or EH_UNWINDING or EH_EXIT_UNWIND
        jnz     nextseh
        mov     edx, dword ptr [esp+12]     // eax = PCONTEXT
        mov     ecx, dword ptr [esp+8]      // ecx = pEstablisherFrame
        mov     dword ptr [edx+CONTEXT.Esp], ecx
        mov     ecx, dword ptr [ecx+10*4]   // ecx = safe_loc_offs
        mov     dword ptr [edx+CONTEXT.Eip], ecx
        xor     eax, eax
        retn
    nextseh:
        xor     eax, eax
        inc     eax     // eax == 1 (ExceptionContinueSearch)
        retn

    }
}

__declspec(naked) void __cdecl CleanupSEHasm_ret ()
{
    __asm
    {
        xor     ecx, ecx
        mov     esp, dword ptr fs:[ecx]   // extra safety
        pop     dword ptr fs:[ecx]
        pop     ecx             // dummy
        mov     dword ptr [esp+1CH], eax
        popad
        add     esp, 4          // dummy
        retn
    }
}

    /*
    // This will not work with some of the kernel functions,
    // but you will be able to get those that are exported
    // only by ordinal. It works well with normal dlls too.
    // Those nasty functions can not be retrieved just from
    // the export directory. That should never happen to
    // simple DLLs.
    */

__declspec(naked) FARPROC __cdecl MyGetProcAddress (HMODULE hModule, char *lpProcName)
{
    __asm
    {
        push    offset scloader_GetProcAddress_exit_fail
        call    SetupSEH

        mov     eax, dword ptr [esp + SEH_STACK + 4]    // hModule

        cmp     word ptr [eax+IMAGE_DOS_HEADER.e_magic], IMAGE_DOS_SIGNATURE
        jne     scloader_GetProcAddress_exit_fail
        mov     ecx, dword ptr [eax+IMAGE_DOS_HEADER.e_lfanew]
        add     ecx, eax
        cmp     dword ptr [ecx+IMAGE_NT_HEADERS.Signature], IMAGE_NT_SIGNATURE
        jne     scloader_GetProcAddress_exit_fail
        cmp     word ptr [ecx+IMAGE_NT_HEADERS.OptionalHeader.Magic], IMAGE_NT_OPTIONAL_HDR32_MAGIC
        jne     scloader_GetProcAddress_exit_fail

        // sizeof (IMAGE_DATA_DIRECTORY) == 8, IMAGE_DIRECTORY_ENTRY_EXPORT == 0
        // Getting RVA of export directory:
        mov     ecx, [ecx + (IMAGE_DIRECTORY_ENTRY_EXPORT * 8) + IMAGE_NT_HEADERS.OptionalHeader.DataDirectory]
        // eax: ImageBase
        // ecx: IMAGE_EXPORT_DIRECTORY RVA that can be zero!!!

        jecxz   scloader_GetProcAddress_exit_fail
        xchg    ebx, eax        // mov ebx, eax  with 1 byte opcode
        lea     edi, [ebx+ecx]  // edi: export_dir VA (not RVA!!!)

        mov     eax, dword ptr [esp + SEH_STACK + 8]    // lpProcName
        cmp     eax, 0FFFFH
        jbe     scloader_GetProcAddress_ordinal

        // eax: lpProcName
        // ebx: ImageBase
        // edi: export_dir VA

        // search by name
        mov     ecx, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfNames]
        mov     edx, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNames]
        add     edx, ebx

        // edx: AddresOfNames VA
        // eax: lpFuncName
        // ecx: ciklusváltozó

scloader_GetProcAddress_search_name_loop:
        jecxz   scloader_GetProcAddress_exit_fail
        dec     ecx

        pushad
        mov     edx, dword ptr [edx+ecx*4]
        add     edx, ebx
        push    edx
        push    eax
        call    dword ptr [lstrcmp]
        or  eax, eax
        popad
        jnz     scloader_GetProcAddress_search_name_loop

        mov     eax, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals]
        add     eax, ebx
        movzx   eax, word ptr [eax+ecx*2]
        jmp     short scloader_GetProcAddress_func_by_index

scloader_GetProcAddress_ordinal:
        // search by ordinal
        sub     eax, [edi+IMAGE_EXPORT_DIRECTORY.Base]
        jc      scloader_GetProcAddress_exit_fail  // !!!!!! bugfix

scloader_GetProcAddress_func_by_index: // !!!!! this label was under the following 2 instructions.
        cmp     eax, [edi+IMAGE_EXPORT_DIRECTORY.NumberOfFunctions]
        jae     scloader_GetProcAddress_exit_fail
        // eax: index to AddressOfFunctions array
        mov     ecx, [edi+IMAGE_EXPORT_DIRECTORY.AddressOfFunctions]
        add     ecx, ebx
        mov     eax, [ecx+eax*4]
        add     eax, ebx
        jmp     short scloader_GetProcAddress_exit

        // The exception handler will jump here on error.
scloader_GetProcAddress_exit_fail:
        xor     eax, eax

scloader_GetProcAddress_exit:   // eax: return value
        jmp     CleanupSEHasm_ret
    }
}




    /*
    // Hiding and unhiding a module:
    //
    // HMODULE hMyDll = LoadLibrary ("xenominator.dll");
    // if (hMyDll)
    // {
    //     DWORD UnhideHandle = HideModule (hMyDll);
    //     UnhideModule (UnhideHandle);
    //     FreeLibrary (hMyDll);
    // }
    //
    // The return value of HideModule is zero on error.
    */

__declspec(naked) DWORD __cdecl HideModule (HMODULE hModule)
{
    static char         kernel32_name[] = "KERNEL32";
    static FARPROC      kernel32_23 = NULL;

    __asm
    {
        cmp     dword ptr [esp+4], 0    // hModule
        jne     hide_mod_nozero_mod
        xor     eax, eax
        retn
hide_mod_nozero_mod:

        push    offset hide_mod_not_found
        call    SetupSEH

        mov     ax, ds
        test    al, 4
        mov     eax, dword ptr [esp + SEH_STACK + 4]  // hModule
        mov     ebx, dword ptr fs:[30H]
        jnz     win9x

        mov     ebx, dword ptr [ebx+0CH]
        add     ebx, 0CH
        mov     edx, dword ptr [ebx]

hide_mod_search_loop:
        cmp     edx, ebx
        je      hide_mod_not_found
        cmp     dword ptr [edx+18H], eax
        je      hide_mod_found
        mov     edx, dword ptr [edx]
        jmp     short hide_mod_search_loop

hide_mod_found:
        push    2
        pop     ecx     ; ciklusváltozó.
hide_mod_loop:
        mov     esi, dword ptr [edx+ecx*8]
        mov     edi, dword ptr [edx+ecx*8+4]
        mov     dword ptr [esi+4], edi
        mov     dword ptr [edi], esi
        dec     ecx
        jns     hide_mod_loop

        jmp     hide_mod_end
hide_mod_not_found:
        xor     edx, edx
hide_mod_end:
        xchg    eax, edx        // mov eax,edx
        jmp     CleanupSEHasm_ret

win9x:
        /*
        // eax: hModule
        // ebx: PDB
        // Getting pointer to kernel32's internal module
        // table pointer list. It can be done universally
        // only with a dirty trick: after calling
        // kernel32#23 ecx will contain the correct pointer.
        // This was tested on both Win95 and Win98SE
        */

        xchg    edi, eax    // mov edi,eax

        mov     eax, kernel32_23
        or      eax, eax
        jnz     hide_mod_k32_23_ok  // address is OK.

        push    offset kernel32_name
        call    dword ptr [GetModuleHandle]
        or      eax, eax
        jz      hide_mod_not_found

        push    23
        push    eax
        call    MyGetProcAddress
        pop     ecx
        pop     ecx     // Clean stack
        mov     kernel32_23, eax

hide_mod_k32_23_ok:
        or      eax, eax
        jz      hide_mod_not_found

        push    0
        call    eax

        /*
        // ecx: pointer to PIMTE table regardless of
        // the succes of kernel32#23 :)
        // We will walk through the MODREF list
        // and search for our handle using PIMTE
        // since module handles are only in PIMTEs
        // and MODREFs contain only indexes to the
        // PIMTE table.
        */

        lea     esi, dword ptr [ebx+4CH]

hide_mod_search_loop2:
        mov     eax, dword ptr [esi]    // PMODREF
        or      eax, eax
        jz      hide_mod_not_found
        movzx   edx, word ptr [eax+10H]
        // edx: index to PIMTE table

        mov     edx, dword ptr [ecx+edx*4]
        // edx: PIMTE of actual MODREF

        mov     edx, dword ptr [edx+4]  // PIMAGE_NT_HEADERS
        cmp     dword ptr [edx+IMAGE_NT_HEADERS.OptionalHeader.ImageBase], edi
        je      hide_mod_found2
        xchg    esi, eax        // mov esi,eax
        jmp     short hide_mod_search_loop2

hide_mod_found2:
        // Unlink current modref (eax)
        mov     ecx, dword ptr [eax]
        mov     dword ptr [esi], ecx

        jmp     CleanupSEHasm_ret
    }
}




__declspec(naked) void __cdecl UnhideModule (DWORD unhide)
{
    __asm
    {
        cmp     dword ptr [esp+4], 0
        jne     hide_mod_not_null
        retn

hide_mod_not_null:
        push    offset CleanupSEHasm_ret
        call    SetupSEH

        mov     ax, ds
        test    al, 4
        mov     eax, [esp+SEH_STACK+4]
        mov     ebx, dword ptr fs:[30H]
        jnz     win9x

        mov     ebx, dword ptr [ebx+0CH]
        add     ebx, 0CH

        push    3
        pop     ecx

unhide_mod_loop:
        mov     edx, dword ptr [ebx]
        mov     dword ptr [eax], edx
        mov     dword ptr [eax+4], ebx
        mov     dword ptr [ebx], eax
        mov     dword ptr [edx+4], eax
        add     eax, 8
        add     ebx, 8
        loop    unhide_mod_loop
        jmp     CleanupSEHasm_ret

win9x:  // eax: PMODREF
        // Just re-link the PMODREF to head of the list
        mov     ecx, dword ptr [ebx+4CH]
        mov     dword ptr [eax], ecx
        mov     dword ptr [ebx+4CH], eax
        jmp     CleanupSEHasm_ret
    }
}




int main ()
{
    static char     cDllName[] = "dll.dll";

    printf ("Loading %s ...\n", cDllName);
    HMODULE hDll = LoadLibrary (cDllName);

    if (!hDll)
    {
        printf ("Error loading dll!\n");
        return -1;
    }

    printf ("Hiding module...\n");
    DWORD unhide = HideModule (hDll);
    printf ("UnhideHandle: %x\n", unhide);

    // Testing module function that should not work like
    // Process32First and Process32Next...

    char cBuff[MAX_PATH];
    printf ("GetModuleFileName result: %d\n", GetModuleFileName (hDll, cBuff, sizeof cBuff));

    printf ("Unhiding module...\n");
    UnhideModule (unhide);

    // Now module functions should should work again:
    printf ("GetModuleFileName result: %d\n", GetModuleFileName (hDll, cBuff, sizeof cBuff));

    printf ("Hiding module again...\n");
    unhide = HideModule (hDll);
    printf ("UnhideHandle: %x\n", unhide);

    // FreeLibrary should fail.
    printf ("FreeLibrary: %d\n", FreeLibrary (hDll));

    printf ("Unhiding module...\n");
    UnhideModule (unhide);

    // FreeLibrary should rock:
    printf ("FreeLibrary: %d\n", FreeLibrary (hDll));

    return 0;

    // You should always unhide modules at least before
    // you exit the process to let windows free the library.
    // You can temporarily unhide a module to use functions
    // that require a HMODULE
}
XeNotRoN 15 0FF11|\|3   Reply With Quote

Old 06-30-2008, 03:50 PM   #3 (permalink)
Perma
rol 3905h, 8
Senior Member
Administrator

Saint
 
Perma's Avatar
 
Join Date: Jul 2004
Location: Canada
Posts: 5,414
Perma has disabled reputation
Default

Thanks for your input Xenotron! The hidemodule snippet was originally a piece by PizzaPan over on his website, the name of which escapes me. I hadn't been focusing on backwards compatibility to 9x clients because my loader wouldn't work on 9x systems anyhow.

But it's cool to know it can be done that way! I also think that's a very cool idea to be able to detach windows from the main StarCraft window.
Perma 15 0|\|11|\|3 |\|0\/\/   Reply With Quote

Old 06-30-2008, 11:59 PM   #4 (permalink)
kovarex

Heretic
 
Join Date: Apr 2008
Posts: 28
kovarex is an unknown quantity at this point
Default

Thank you for this A LOT.
This will help us a lot in our BWAI project, I guess we would like to use the source code as a whole, would we be allowed to modify it in that case?
(and yes our project is open source)
kovarex 15 0FF11|\|3   Reply With Quote

Old 07-01-2008, 02:25 AM   #5 (permalink)
Perma
rol 3905h, 8
Senior Member
Administrator

Saint
 
Perma's Avatar
 
Join Date: Jul 2004
Location: Canada
Posts: 5,414
Perma has disabled reputation
Default

Yes, you can use any part or all of the source code as long as credit is given.
Perma 15 0|\|11|\|3 |\|0\/\/   Reply With Quote

Old 07-01-2008, 03:04 AM   #6 (permalink)
RcProductionz
Banned

Heretic
 
Join Date: Jun 2008
Posts: 18
RcProductionz is an unknown quantity at this point
Default

What is pizzapan website anyways?
RcProductionz 15 0FF11|\|3   Reply With Quote

Old 07-01-2008, 04:45 AM   #7 (permalink)
ulliklliwi

Disciple
 
ulliklliwi's Avatar
 
Join Date: May 2007
Location: The Code Cave after the JMP Gate
Posts: 545
ulliklliwi has a spectacular aura about
Send a message via MSN to ulliklliwi
Default

idk y people use this gay module hide function. Cuz you can still get the module information. its very ez if you use ur head...
ulliklliwi 15 0FF11|\|3   Reply With Quote

Old 07-01-2008, 04:23 PM   #8 (permalink)
XeNotRoN

Deviant
 
XeNotRoN's Avatar
 
Join Date: Mar 2006
Location: Hungary - near to the gates of hell
Posts: 45
XeNotRoN is on a distinguished road
Default

I dont like it either, but its not that bad. The best way is loading the dll with own code, but then you dont have a HMODULE, and having no resource functions can be pain in the ass (Dialogs etc...) - but thats not a problem in most cases with sc plugins. And by writing a FindResource(), most of the resource functions can be emulated.
Maybe not in the best place, but I attached an example. This dll loading routine does the same as scloader2b's -dllex parameter.

Here is our primitive slave DLL that wants us to load it "manually":
building dll.c, dll.def:
cl /c /I<your_include_dir> dll.c
link /subsystem:windows /dll /def:dll.def dll.obj

The code that is able to load the DLL: (3 files)
load_dll_test.cpp, load_dll.cpp, load_dll.h

Known issues with "manual load":
  • You do not have a HMODULE. The Imagebase you get can only be used with one of the MyGetProcAddress functions but only when you loaded the DLL with headers. The most painful thing is that you can not use resource functions. These functions can also be emulated. One way to solve the problem is Finding the resource manually and then use Dialog functions that work on memory templates. Some of the Resource functions work on binary data, for example one of my favorites is CreateIconFromResource that creates cursor/icon from anywhere, you must point to the icon data where its BITMAP_INFO_HEADER begins, and 2 words back if you create a cursor and you must store the hotspot before the BITMAP_INFO_HEADER in that 2 words. There are several tricks to solve resource handling, but I usually convert the data I use to C/pascal array (source code) and compile it to the code. This is the easiest way to go.
  • You wont recive DLL_THREAD_ATTACH/DETACH notifications. You can emulate them with the lpfDllMain member of LOAD_DLL_INFO if you have another real workhorse DLL.
  • LoadDLL does not give you detailed error message when an import resolving error occurs. You dont know what DLL or function is missing. Patch the code yourself, its not that hard.
The sample code uses 0 as dwFalgs when it call LoadDLL or any of its descendants that implement the readproc (streaming). When you use antihack use the DLL_NO_HEADERS flag to make it harder to sweep your module.

Own FindResource:
Some win32 functions that may come handy when you load resources by hand after you used the MyFindResource(), MyLoadResource() and MySizeOfResource() functions and you have the pointer to the raw resource data:
  • ICON and CURSOR
    CreateIconFromResource()
  • DIALOG
    CreateDialogIndirect()
    CreateDialogIndirectParam()
  • MENU
    LoadMenuIndirect()

The FindResource sources can be compiled as both ANSI and UNICODE.

The sources were compiled under VC++6.
Attached Files
File Type: zip load_dll.zip (10.0 KB, 10 views)
File Type: zip FindResource.zip (11.4 KB, 8 views)
XeNotRoN 15 0FF11|\|3   Reply With Quote

Old 07-02-2008, 11:19 AM   #9 (permalink)
Zephyrix
Ereetu.
Senior Member
Game Hacking Staff

High Priest
 
Zephyrix's Avatar
 
Join Date: Oct 2005
Location: xor 1D27,1337
Posts: 1,565
Zephyrix is a name known to allZephyrix is a name known to allZephyrix is a name known to allZephyrix is a name known to all
Default

Quote:
Originally Posted by Perma View Post
Thanks for your input Xenotron! The hidemodule snippet was originally a piece by PizzaPan over on his website, the name of which escapes me. I hadn't been focusing on backwards compatibility to 9x clients because my loader wouldn't work on 9x systems anyhow.

But it's cool to know it can be done that way! I also think that's a very cool idea to be able to detach windows from the main StarCraft window.

Gamedeception I believe.
__________________


Zephyrix 15 0FF11|\|3   Reply With Quote

Old 07-12-2008, 07:18 PM   #10 (permalink)
Jailout2000

Heretic
 
Jailout2000's Avatar
 
Join Date: Mar 2007
Location: I miss Arizona, U.S.
Posts: 39
Jailout2000 is on a distinguished road
Send a message via AIM to Jailout2000 Send a message via MSN to Jailout2000 Send a message via Yahoo to Jailout2000 Send a message via Skype™ to Jailout2000
Default

I have a solution to fix your drag n drop problem with the windows, I noticed that when you moved the windows around in the video, the mouse would always be at the top left of the window, not where the mouse was being held at.

To fix this, simply make 2 properties.

Before you start dragging, do this:

PropertyX = Window's MouseX
PropertyY = Window's MouseY

While your dragging, do this:

Set window left to BW's MouseX subtracting PropertyX
Set window top to BW's MouseY subtracting PropertyY

You can play around with this to see what I mean, if it doesn't make sense or it sounds like it won't work.

Hope this helps you in your next patch/version and/or other users that plan to use this in they're hack.

-Jailout2000
__________________
My Website | My Battle.net Bot | GroupChat

Last edited by Jailout2000 : 07-12-2008 at 07:41 PM. Reason: Fixed a mathematical error, my bad!
Jailout2000 15 0FF11|\|3   Reply With Quote

Old 07-13-2008, 02:44 AM   #11 (permalink)
cak3

Deviant
 
cak3's Avatar
 
Join Date: Jun 2008
Posts: 115
cak3 is an unknown quantity at this point
Default Thanks Perma

Thank you for the source perma.
I'm using this for my status hack on operations currently in progress (upgrades percentage etc).

I'm also going to be adding a enemy selects log.
Thank you again, I wouldn't do this without this code here.
__________________




Quote:
Originally Posted by Zynastor View Post
Learn how to speak English properly and no winbot will never be patched. There probably wont even be another sc patch anyways and if blizzard wanted to patch the zerg mineral hack they would have done that in the last 2 patches so lol, haha lol.. lol... muahaha.... lol
cak3 15 0FF11|\|3   Reply With Quote

Old 07-13-2008, 03:48 AM   #12 (permalink)
Perma
rol 3905h, 8
Senior Member
Administrator

Saint
 
Perma's Avatar
 
Join Date: Jul 2004
Location: Canada
Posts: 5,414
Perma has disabled reputation
Default

Good to know it's being put to use!
Perma 15 0|\|11|\|3 |\|0\/\/   Reply With Quote

Old 07-13-2008, 05:55 AM   #13 (permalink)
K? Pŕo?ćtiόnŹ
=)
Senior Member
Retired Staff Member

Messiah
 
K? Pŕo?ćtiόnŹ's Avatar
 
Join Date: Oct 2004
Location: Okinawa
Posts: 9,347
K? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond reputeK? Pŕo?ćtiόnŹ has a reputation beyond repute
Send a message via AIM to K? Pŕo?ćtiόnŹ
Default

Quote:
Originally Posted by Perma View Post
Here is the source code to my Exhale interface project for StarCraft. Some of it is a little bit messy as I was experimenting with some features, but most of the core functions are pretty slick.

Feel free to use this source in your own projects, giving credit where it's due. Do try to release your work open source - it helps more people learn. If you have questions about the source, post them here or contact me via private message.


Credits
Zephyrix - A great solution to refreshing issues.
PizzaPan - Module hiding function.
Kc - Original drawing function.

And thanks to all of the 1ovely pe0ple that have helped me along the way.
I found it!
__________________
K? Pŕo?ćtiόnŹ 15 0FF11|\|3   Reply With Quote

Old 07-13-2008, 02:38 PM   #14 (permalink)
De
Private Hack User
Banned

Blessed
 
Join Date: Dec 2005
Location: Canada
Posts: 2,520
De is just really niceDe is just really nice
Default

Lol kc.
De 15 0FF11|\|3   Reply With Quote

Old 07-13-2008, 04:51 PM   #15 (permalink)
Perma
rol 3905h, 8
Senior Member
Administrator

Saint
 
Perma's Avatar
 
Join Date: Jul 2004
Location: Canada
Posts: 5,414
Perma has disabled reputation