꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
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  댓글주소  수정/삭제  댓글쓰기

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