네이트온은 쓰다 보면, 다른 데서 로그인하거나 해서 튕긴 경우엔 다시 로그인하기가 귀찮다. 저장된 아이디와 비밀번호를 다 날려버리기 때문이다.
피씨방 등에서 접속하는 일이 많은 일반적인 사람들 기준에서는 저렇게 날려주는게 보안상 이로울 것이다. 아무 생각도 없이 공용 피씨방에서도 자동로그인 옵션을 넣어서 로그인했다가 피싱에 이용당한다던가 하는 일이 많은, 보안 개념이라곤 개미똥꾸멍만큼도 없는 한국인에게 있어서는 정말 유용하다. 유용하긴 하다. 근데 그런 기능은 선택할 수 있게 해 주면 좋지 않을까. 나처럼 두 컴퓨터를 쓰는 경우에는 번갈아가며 로그인해야하는데 저장된 비번이 날아가대니 얼마나 불편한지 모른다. MSN을 좀 닮아주면 안될까.
푸념은 여기까지 하고, 목마른 자가 우물을 판다고 직접 프로그램을 짜 보았다. Win32 API를 써야 할테니 C나 C++을 쓰는 편이 낫겠지만, 연습도 해보고 그냥 끄적거리기엔 루비가 훨 편하니까 루비를 사용해 보았다. 사용한 것은 루비 1.8.7 patchlevel 0 i386-mswin32 버전과 win32api 젬을 사용했다.
require 'Win32API'
class NateOnAutoLogin
@@instance = nil
@@find_window_ex = Win32API.new 'user32', 'FindWindowExA', 'LLPP', 'L'
@@send_message = Win32API.new 'user32', 'SendMessage', 'LLLP', 'L'
@@get_window_text = Win32API.new 'user32', 'GetWindowTextA', 'LPL', 'L'
WM_KEYDOWN = 256
WM_KEYUP = 257
WM_CHAR = 258
WM_COMMAND = 273
WM_GETTEXT = 13
VK_END = 35
VK_UP = 38
IDC_LOGIN = 0x3f2
IDC_OTHER_LOGIN = 0x3f6
IDC_DO_LOGIN = 0x3f5
class << self
alias orig_new new
def new
if @@instance.nil?
@@instance = NateOnAutoLogin.orig_new
else
@@instance
end
end
protected :orig_new
end
def login(id, pass)
local_id, host = id.split '@'
hwnd_nateon = @@find_window_ex.call 0, 0, nil, 'NateOn'
sub = @@find_window_ex.call hwnd_nateon, 0, nil, nil
login_dlg = @@find_window_ex.call sub, 0, '#32770', nil
@@send_message.call login_dlg, WM_COMMAND, IDC_OTHER_LOGIN, nil
@@send_message.call login_dlg, WM_COMMAND, IDC_DO_LOGIN, nil
local_id_wnd = @@find_window_ex.call login_dlg, 0, 'Edit', nil
local_id.each_byte {|chr| @@send_message.call local_id_wnd, WM_CHAR, chr, 0}
host_wnd_a = @@find_window_ex.call login_dlg, 0, 'ComboBox', nil
host_wnd_b = @@find_window_ex.call login_dlg, host_wnd_a, 'ComboBox', nil
if @@find_window_ex.call(host_wnd_a, 0, nil, nil) == 0
host_provided_wnd = host_wnd_a
host_manual_wnd = host_wnd_b
else
host_provided_wnd = host_wnd_b
host_manual_wnd = host_wnd_a
end
@@send_message.call host_provided_wnd, WM_KEYDOWN, VK_END, nil
@@send_message.call host_provided_wnd, WM_KEYUP, VK_END, nil
@@send_message.call host_provided_wnd, WM_KEYDOWN, VK_UP, nil
@@send_message.call host_provided_wnd, WM_KEYUP, VK_UP, nil
host.each_byte {|chr| @@send_message.call host_manual_wnd, WM_CHAR, chr, nil }
password_wnd = @@find_window_ex.call login_dlg, local_id_wnd, 'Edit', nil
pass.each_byte {|chr| @@send_message.call password_wnd, WM_CHAR, chr, nil }
@@send_message.call login_dlg, WM_COMMAND, IDC_LOGIN, nil
end
end
class NateOnAutoLogin
@@instance = nil
@@find_window_ex = Win32API.new 'user32', 'FindWindowExA', 'LLPP', 'L'
@@send_message = Win32API.new 'user32', 'SendMessage', 'LLLP', 'L'
@@get_window_text = Win32API.new 'user32', 'GetWindowTextA', 'LPL', 'L'
WM_KEYDOWN = 256
WM_KEYUP = 257
WM_CHAR = 258
WM_COMMAND = 273
WM_GETTEXT = 13
VK_END = 35
VK_UP = 38
IDC_LOGIN = 0x3f2
IDC_OTHER_LOGIN = 0x3f6
IDC_DO_LOGIN = 0x3f5
class << self
alias orig_new new
def new
if @@instance.nil?
@@instance = NateOnAutoLogin.orig_new
else
@@instance
end
end
protected :orig_new
end
def login(id, pass)
local_id, host = id.split '@'
hwnd_nateon = @@find_window_ex.call 0, 0, nil, 'NateOn'
sub = @@find_window_ex.call hwnd_nateon, 0, nil, nil
login_dlg = @@find_window_ex.call sub, 0, '#32770', nil
@@send_message.call login_dlg, WM_COMMAND, IDC_OTHER_LOGIN, nil
@@send_message.call login_dlg, WM_COMMAND, IDC_DO_LOGIN, nil
local_id_wnd = @@find_window_ex.call login_dlg, 0, 'Edit', nil
local_id.each_byte {|chr| @@send_message.call local_id_wnd, WM_CHAR, chr, 0}
host_wnd_a = @@find_window_ex.call login_dlg, 0, 'ComboBox', nil
host_wnd_b = @@find_window_ex.call login_dlg, host_wnd_a, 'ComboBox', nil
if @@find_window_ex.call(host_wnd_a, 0, nil, nil) == 0
host_provided_wnd = host_wnd_a
host_manual_wnd = host_wnd_b
else
host_provided_wnd = host_wnd_b
host_manual_wnd = host_wnd_a
end
@@send_message.call host_provided_wnd, WM_KEYDOWN, VK_END, nil
@@send_message.call host_provided_wnd, WM_KEYUP, VK_END, nil
@@send_message.call host_provided_wnd, WM_KEYDOWN, VK_UP, nil
@@send_message.call host_provided_wnd, WM_KEYUP, VK_UP, nil
host.each_byte {|chr| @@send_message.call host_manual_wnd, WM_CHAR, chr, nil }
password_wnd = @@find_window_ex.call login_dlg, local_id_wnd, 'Edit', nil
pass.each_byte {|chr| @@send_message.call password_wnd, WM_CHAR, chr, nil }
@@send_message.call login_dlg, WM_COMMAND, IDC_LOGIN, nil
end
end
윈도 구조를 Spy++로 분석한 다음, SendMessage를 써서 키를 눌러주었다. 복잡하지 않다:$
NateOnAutoLogin을 싱글톤으로 구현했는데. new 메소드로 생성되는 객체 자체가 하나만 존재하게끔 손보아 보았다.
쓰기 위해서는, NateOnAutoLogin.new.login 'gwangyi@sfc.or.kr', ';didw;tsmv' 와 같은 식으로 해 주면 로그인된다.
'프로그래밍 > Ruby' 카테고리의 다른 글
| ruby 동영상 플레이어 라이브러리 with DirectShow (0) | 2010/04/18 |
|---|---|
| Ruby-GTK2 0.19.3 for Windows (0) | 2010/04/13 |
| 네이트온 자동 로그인 (0) | 2009/12/04 |
| 공개 한글 폰트 다운로더 (0) | 2009/11/16 |
| Ruby-GNOME2 0.18 One-Click Installer for Windows (0) | 2009/10/20 |
| rubyscript2exe 로 ruby-gnome2를 이용한 어플 패킹하기 (2) | 2009/02/02 |
