프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 친절한티스

요즘 디아블로 3를 즐기고 있는데 로그인 에러 때문에 빡치더군요. 돈 주고 게임을 샀는데 할 수가 없어요. 그러다 로그인 과정에 일정한 패턴도 있겠다. 한번 자동으로 만들어보자 해서 만들어보게 되었습니다. ( 이렇게 프로그래밍 스킬을 써먹는 것 이지요. )


열어줘!! 열어달라고!!!


일단 크게 3 부분이 필요하다는 것을 정리했습니다.


1. 전역 키 후킹

매크로 프로그램 같은 경우 게임의 배경에서 돌아가야 합니다. 포커스가 디아블로에 있다 하더라도 자동 로그인 프로그램이 on/off 될수 있도록 전역적인 키 후킹이 필요합니다. ( 예. F1로 자동 로그인 켜기, F2로 자동 로그인 끄기 )


2. 패턴화된 작업을 자동화

보통 로그인이 과정이 아이디는 입력해놓으면 고정되고, 패스워드 입력 -> 접속 버튼 클릭 -> (에러난 경우 ) 에러창 출력 -> 에러창 닫기 -> 패스워드 입력 -> ... 대략 이렇습니다. 이 과정만 자동화 해놓으면 되죠.


3. 화면 해상도

클릭 해야 될 부분이 해상도 마다 다릅니다. 모든 사람이 1920 * 1080 해상도를 쓰는 것이 아니므로, 클릭 좌표를 비율로 관리해야 했습니다. 일단 제가 사용하는 1680 * 1050 해상도를 기준으로 좌표를 클릭해야 할 좌표들을 얻은 다음 비율을 통해 대부분의 해상도에서 ( 와이드 기준 ) 작동 하도록 하였습니다.


일단 작업 해야될 부분을 정리 했고, 이제 실제로 만들어 보도록 하죠.


먼저 전역 키 후킹 클래스를 만들어봅니다. 구글링을 해보니 이미 CodeProject에 좋은 샘플이 있더군요. 이것을 기반으로 작업해보겠습니다. ( 출처 : http://www.codeproject.com/Articles/19004/A-Simple-C-Global-Low-Level-Keyboard-Hook )


// 후킹에 필요한 Win32API를 임포트
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);

// 후킹 프로시저 함수와 후킹 데이타 구조체 정의
delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
keyboardHookProc mkeyboardHookProc;
struct keyboardHookStruct
{
	public int vkCode;
	public int scanCode;
	public int flags;
	public int time;
	public int dwExtraInfo;
}

// 후킹 후 불려질 콜백 함수 정의
public delegate bool CustomKeyEventHandler(Key k);
public event CustomKeyEventHandler CustomKeyDown;
public event CustomKeyEventHandler CustomKeyUp;

// 후킹 시작
const int WH_KEYBOARD_LL = 13;
public void hook() 
{
	IntPtr hInstance = LoadLibrary("User32");
 	mkeyboardHookProc = hookProc;
 	hhook = SetWindowsHookEx(WH_KEYBOARD_LL, mkeyboardHookProc, hInstance, 0);
}

// 후킹 끝
public void unhook() 
{
	UnhookWindowsHookEx(hhook);
}

// 후킹 프로시저
public int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
{
	if (code >= 0) 
    {
		Key key = KeyInterop.KeyFromVirtualKey(lParam.vkCode);      
        
        // 등록된 키가 눌러졌으면 
		if (HookedKeys.Contains(key)) 
        {
            bool bHandled = false;
			if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && CustomKeyDown != null)
            {
                bHandled = CustomKeyDown(key);
			}
            else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && CustomKeyUp != null)
            {
                bHandled = CustomKeyUp(key);
			}
            if (bHandled)
				return 1;
		}
	}
	return CallNextHookEx(hhook, code, wParam, ref lParam);
}


코드는 상당히 간단합니다. HookedKeys에 후킹 하고 싶은 키과 불려질 함수를 등록 해두고, 해당 키가 입력 되었을때 등록된 함수가 호출 되는 방식입니다. (KeyDown, KeyUp을 구분 해둠)


실제 사용하는 부분입니다.


// F1과 F2키를 후킹 하도록 한다.
// 위의 키가 눌리면 CustomKeyUpEvent가 호출
mGlobalHooker = new GlobalHooker();
mGlobalHooker.HookedKeys.Add(Key.F1);
mGlobalHooker.HookedKeys.Add(Key.F2);
mGlobalHooker.CustomKeyUp += new CustomKeyEventHandler(CustomKeyUpEvent);


이제 키 후킹은 되었으니 자동 로그인 부분을 만들어 보죠. 제가 생각하는 구조는 필요한 암호를 입력 받아놓고, 패스워드 필드에 패스워드 입력 후 ( 붙여넣기 ) 접속 버튼을 클릭. 그 다음 에러 창이 뜨고, 에러창 닫기를 클릭. 다시 패스워드 필드를 클릭 하고 ( 가끔 포커스가 아이디 필드로 날아가니 ) 다시 패스워드 입력 후... 이후 반복 작업입니다.




대략 4가지 일을 해야 합니다. 이 모든 일이 한번에 일어나면 이벤트 동작이 제대로 안됩니다. 이전 이벤트가 씹히기도 하죠. 그래서 각 이벤트를 일정 딜레이를 주고, 발생하도록 합니다. 일단 그전에 클릭 해야될 좌표를 구해야 합니다. 제가 1680 * 1050 해상도를 사용하는데, 이 해상도를 기준으로 클릭 좌표를 화면 해상도 비율로 구해놓았습니다. 그렇기 때문에 해상도가 변해도 클릭해야 될 곳을 정확히 클릭하도록 했습니다.

// 마우스와 키 입력 이벤트를 생성하기 위한 Win32Api 불러오기
[DllImport("user32.dll")]
static extern void keybd_event(byte vk, byte scan, int flags, int extrainfo);
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);
[DllImport("USER32.dll", CallingConvention = CallingConvention.StdCall)]
static extern void SetCursorPos(uint X, uint Y);

// 현재 화면 해상도(게임 해상도)를 비율로 구함
// 이 작업은 자동 로그인이 시작 될때 실행 됨
mScreenWidthRatio = 1.0 / 1680 * SystemParameters.PrimaryScreenWidth;
mScreenHeightRatio = 1.0 / 1050 * SystemParameters.PrimaryScreenHeight;

// 작업 이벤트를 순차적으로 등록
mEvents = new ArrayList();
mEvents.Add(new LoginEventHandler(LoginEvent1));
mEvents.Add(new LoginEventHandler(LoginEvent2));
mEvents.Add(new LoginEventHandler(LoginEvent3));
mEvents.Add(new LoginEventHandler(LoginEvent4));

// 이벤트 1 - 패스워드 필드 클릭
void LoginEvent1()
{
    double CursorX = mScreenWidthRatio * 835;
    double CursorY = mScreenHeightRatio * 686;

    SetCursorPos((uint)CursorX, (uint)CursorY);
    mouse_event(LBUTTONDOWN | LBUTTONUP, (uint)CursorX, (uint)CursorY, 0, 0);
}

// 이벤트 2 - 패스워드 붙여넣기
void LoginEvent2()
{
    keybd_event(CTRLKEY, 0, 0, 0);
    keybd_event(VKEY, 0, 0, 0);
    keybd_event(CTRLKEY, 0, KEYEVENT_UP, 0);
}

// 이벤트 3 - 접속 버튼 클릭
void LoginEvent3()
{
    double CursorX = mScreenWidthRatio * 835;
    double CursorY = mScreenHeightRatio * 835;

    SetCursorPos((uint)CursorX, (uint)CursorY);
    mouse_event(LBUTTONDOWN | LBUTTONUP, (uint)CursorX, (uint)CursorY, 0, 0);
}

// 이벤트 4 - 에러37 확인 버튼 누르기
void LoginEvent4()
{
    double CursorX = mScreenWidthRatio * 835;
    double CursorY = mScreenHeightRatio * 615;

    SetCursorPos((uint)CursorX, (uint)CursorY);
    mouse_event(LBUTTONDOWN | LBUTTONUP, (uint)CursorX, (uint)CursorY, 0, 0);
}


각 이벤트들을 배열리스트에 담아두고 지정된 딜레이 시간마다 순차적으로 호출 되게 합니다. 여기서는 F1키가 입력되면 작업을 실행도록 합니다.

// 타이머를 생성
TimerClock = new DispatcherTimer();
TimerClock.Tick += new EventHandler(Timer_Tick);

// 등록된 키가 눌리면 불려지는 함수
bool CustomKeyUpEvent(Key k)
{
    switch (k)
    {
        case Key.F1:
            {
                if (!TimerClock.IsEnabled)
                {
                    // 해상도 비율로 사용 가능하게 비율을 구함
                    mScreenWidthRatio = 1.0 / 1680 * SystemParameters.PrimaryScreenWidth;
                    mScreenHeightRatio = 1.0 / 1050 * SystemParameters.PrimaryScreenHeight;

                    // 실행될 프로시저 인덱스
                    mCurrEventIDX = 0;
                            
                    // 입력된 딜레이 값을 지정
                    // 입력된 패스워드를 클립보드에 복사
                    miDelayTime = Convert.ToInt32(textBox1.Text);
                    Clipboard.SetData(DataFormats.Text, textBox2.Text);

                    // 타이머 실행
                    TimerClock.Interval = new TimeSpan(0, 0, 0, 0, miDelayTime);
                    TimerClock.Start();
                }
                else
                {
                    TimerClock.Stop();
                }
            }
            return true;

        // F2키는 종료. 종료 되기전에 클립보드를 비운다.
        case Key.F2:
            {
                Clipboard.SetData(DataFormats.Text, "");
                Application.Current.Shutdown();
            }
            return true;
        default: return false;
    }
}

// 타이머에 의해서 호출된다
// 호출될때마다 순차적으로 등록된 이벤트 함수를 호출한다
void Timer_Tick(object sender, EventArgs e)
{
    if (0 == mEvents.Count)
        return;

    if (mCurrEventIDX >= mEvents.Count)
        mCurrEventIDX = 0;

    (mEvents[mCurrEventIDX] as LoginEventHandler)();
    ++mCurrEventIDX;
}

대략 이걸로 기본적인 동작은 하게 됩니다. 이렇게 만들어진 결과물~ 쨔란~ 알고 보면 별거 아님.


Diablo3AutoLoginV2.zip


인증 중인 창을 닫는 부분을 수정했습니다.

댓글을 달아 주세요

  1. 완전 2012.05.20 17:07  댓글주소  수정/삭제  댓글쓰기

    오류나는데용?

  2. Favicon of http://bluekms21.blog.me 크로스 2012.05.20 22:53  댓글주소  수정/삭제  댓글쓰기

    소..소프트웨어적으로 일종의 오토를 만드셨어..ㄷㄷㄷㄷ
    랄까, 요즘 대부분의 온라인게임에선 소프트웨어 오토를 막고있기때문에
    아마 다른건 더 안되겠죠??

  3. 로엔그람 2012.05.20 23:02  댓글주소  수정/삭제  댓글쓰기

    저는 잘 됩니다~ 완전 멋지십니다^^

  4. Favicon of http://lunapiece.net Lyn 2012.05.21 09:41  댓글주소  수정/삭제  댓글쓰기

    블리자드는 게임에 보안 안하기로 유명하니 ㅋㅋ

  5. Favicon of https://gamedevforever.com denoil 2012.05.21 10:05 신고  댓글주소  수정/삭제  댓글쓰기

    우왕 유용한 프로그램 감사합니다!! 정말 필요했어요 ㅠㅠ

  6. 인자인자유인자 2012.05.21 17:38  댓글주소  수정/삭제  댓글쓰기

    아~ 필요하던 프로그램이군요..일일이 비밀번호 넣기 귀찮았는데...
    그런데 OPT설정해 놓으면 이 프로그램 사용 못하나요??

  7. Fatigue 2012.05.21 21:54  댓글주소  수정/삭제  댓글쓰기

    1920x1080 해상도도 쓰고 다른해상도도 써봤지만 클릭좌표가 어긋나네요 ㅠㅠ어떻게 해야하죠 ㅠ

  8. Favicon of https://blueasa.tistory.com blueasa 2012.05.22 02:31 신고  댓글주소  수정/삭제  댓글쓰기

    http://blueasa.tistory.com/768

    친절한티스님 덕분에 만들어서 올렸습니다.
    WPF 힘드네요 전.. =ㅅ=;;
    아무튼 덕분에 WPF로 만들어보게 됐습니다. 감사합니다. :)

  9. 고구마 2012.05.22 11:07  댓글주소  수정/삭제  댓글쓰기

    헛 감사합니다 ㅠ_ㅠ
    문제는 잘 모르는 부분이라 @@ 후압
    옮겨적기도 어렵군요 .
    오류가 콸콸콸
    ㅠ_ㅠ c#으로 변환가능한건가요?

  10. Fatigue 2012.05.22 21:55  댓글주소  수정/삭제  댓글쓰기

    창모드가 아닌데도 그러네요 ㅠㅠㅠ 으앙..

  11. 흑화 2012.05.22 21:59  댓글주소  수정/삭제  댓글쓰기


    오토핫키로도 가능할거같네염.
    이미지서치응용하면 가능할거같아염

    • Favicon of https://gamedevforever.com 친절한티스 2012.05.23 21:57 신고  댓글주소  수정/삭제

      네 여러 매크로 프로그램으로도 충분히 가능한 동작입니다. 저는 그냥 WPF로도 이런거 만들수 있다 정도로 알려드리기 위해 써본거 뿐이예요.

  12. Favicon of http://lunapiece.net Lyn 2012.05.23 09:50  댓글주소  수정/삭제  댓글쓰기

    이거 16:9 해상도 에서는 접속중 취소버튼을 눌러버리는 문제가 ...

  13. 풀리쉬 2012.05.23 10:22  댓글주소  수정/삭제  댓글쓰기

    화면 해상도가 코드에 박혀 있는데 이것도 폼에서 입력 받게 해서 여러 해상도로 test 해서 배포하시면 더 유용할듯 합니다.

  14. 스카이뿅 2012.06.01 07:03  댓글주소  수정/삭제  댓글쓰기

    오토핫키를 사용하시면 더욱 간단하게 만드실수 있습니다.

    좌표만 잘 설정해주면 인증창도 닫히지 않게 할수 있죠.^^

    • Favicon of https://gamedevforever.com 친절한티스 2013.05.17 17:24 신고  댓글주소  수정/삭제

      네 맞습니다. 제가 이거 올린 이유는 WPF로 이렇게 직접 만들수 있다는걸 보여주기 위함이죠. 쉽고 빠른걸 원하시면 오토핫키 같은 매크로 프로그램 쓰는게 좋습니다.

  15. 2013.05.17 08:51  댓글주소  수정/삭제  댓글쓰기

    나중에 쓸일있을까 싶어 기억해뒀었는데
    막상 쓸일있어서 훑어보니
    소스는 전체소스도 아니고 파편적으로 나눠져있고
    첨부파일은 실행파일 뿐이네요..;
    도움이 안되네요