不少商业网站都提供了密码输入框ActiveX控件来保护用户密码在输入过程中不被窃取,并加密。
但是有时可能需要做一些程序自动完成某些功能,比如:抓取网页的一些数据。
使用的账户少还好,一个一个通过嗅探器分析,保存加密后的数据。
若是账户多,就麻烦了。此时最好能够通过程序调用这段加密逻辑。
不过,这些控件不少都只提供用户输入接口,而不提供编程接口,即,只能通过用户界面发送消息。
下面的例子就是以淘宝的密码输入框控件为例,使用Swt和JNA来完成这项任务。
其主要思路是:
1. 通过Swt加载该含窗口界面的ActiveX控件。窗口可以不显示。
这是由于这种控件是不能独立显示的,必须有一个外部容器,比如IE浏览器。
(单独的 Swt 加载 ActiveX 的例子请参考 。)
2. 通过JNA调用Windows的相关消息接口模拟键盘发送相关消息。
3. 最后通过Swt的接口调用该控件的方法、属性,获取输出值。
说明:
TestSwtAndJna.java 只是最基本的示例,旨在说明原理。
而附件中的
OleFactory.java 是一个进一步再组织的半成品。
Java&&ActiveX.zip 在针对某个特定的ActiveX控件开发时,需要熟练使用 Visual Studio 中的 OLE-COM Object Viewer 和 Spy++ 这两个工具。
(PS:之所以使用 Java,是因为偶更熟悉Java开发。)
(PPS:附件中没有包含第三方jar包,请自行下载: 、、)
TestSwtAndJna.java (这个只是最基本的示例,)
- import org.eclipse.swt.SWT;
- import org.eclipse.swt.SWTError;
- import org.eclipse.swt.events.SelectionAdapter;
- import org.eclipse.swt.events.SelectionEvent;
- import org.eclipse.swt.layout.FillLayout;
- import org.eclipse.swt.ole.win32.OLE;
- import org.eclipse.swt.ole.win32.OleAutomation;
- import org.eclipse.swt.ole.win32.OleClientSite;
- import org.eclipse.swt.ole.win32.OleFrame;
- import org.eclipse.swt.ole.win32.Variant;
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Menu;
- import org.eclipse.swt.widgets.MenuItem;
- import org.eclipse.swt.widgets.MessageBox;
- import org.eclipse.swt.widgets.Shell;
- import com.sun.jna.Pointer;
- import com.sun.jna.platform.win32.Kernel32;
- import com.sun.jna.platform.win32.User32;
- import com.sun.jna.platform.win32.WinDef.DWORD;
- import com.sun.jna.platform.win32.WinDef.HWND;
- import com.sun.jna.platform.win32.WinDef.LPARAM;
- import com.sun.jna.platform.win32.WinDef.WPARAM;
- public class TestSwtAndJna {
- static OleClientSite clientSite;
- public static void main(String[] args) {
- Display display = new Display();
- Shell shell = new Shell(display);
- shell.setText("Test Password ActiveX Control");
- shell.setLayout(new FillLayout());
- try {
- OleFrame frame = new OleFrame(shell, SWT.NONE);
- clientSite = new OleClientSite(frame, SWT.NONE,
- "{488A4255-3236-44B3-8F27-FA1AECAA8844}");
- clientSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
- addFileMenu(frame);
- } catch (SWTError e) {
- System.out.println("Unable to open activeX control");
- display.dispose();
- return;
- }
- shell.setSize(400, 300);
- shell.open();
- while (!shell.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- display.dispose();
- }
- static void addFileMenu(final OleFrame frame) {
- final Shell shell = frame.getShell();
- Menu menuBar = shell.getMenuBar();
- if (menuBar == null) {
- menuBar = new Menu(shell, SWT.BAR);
- shell.setMenuBar(menuBar);
- }
- MenuItem fileMenu = new MenuItem(menuBar, SWT.CASCADE);
- fileMenu.setText("&Action");
- Menu menuFile = new Menu(fileMenu);
- fileMenu.setMenu(menuFile);
- frame.setFileMenus(new MenuItem[] { fileMenu });
- MenuItem menuHandle = new MenuItem(menuFile, SWT.CASCADE);
- menuHandle.setText("View Activex Container's window handle");
- menuHandle.addSelectionListener(new SelectionAdapter() {
- public void widgetSelected(SelectionEvent e) {
- MessageBox messageBox = new MessageBox(shell,
- SWT.ICON_INFORMATION | SWT.OK);
- messageBox.setText("Info");
- // useful with SpyXX.exe
- messageBox.setMessage("handle = ["
- + Long.toHexString(clientSite.handle).toUpperCase()
- + "]");
- messageBox.open();
- }
- });
- MenuItem menuTextData = new MenuItem(menuFile, SWT.CASCADE);
- menuTextData.setText("View encrypted password");
- menuTextData.addSelectionListener(new SelectionAdapter() {
- public void widgetSelected(SelectionEvent e) {
- OleAutomation ole = new OleAutomation(clientSite);
- int[] rgdispid = ole.getIDsOfNames(new String[] { "TextData" });
- Variant var = ole.getProperty(rgdispid[0]);
- MessageBox messageBox = new MessageBox(shell,
- SWT.ICON_INFORMATION | SWT.OK);
- messageBox.setText("Info");
- String str = null;
- if (OLE.VT_NULL == var.getType()) {
- str = null;
- } else if (OLE.VT_EMPTY == var.getType()) {
- str = "";
- } else {
- str = var.getString();
- }
- messageBox.setMessage("encrypted password = [" + str + "]");
- messageBox.open();
- }
- });
- MenuItem menuDelete = new MenuItem(menuFile, SWT.CASCADE);
- menuDelete.setText("Delete last input char");
- menuDelete.addSelectionListener(new SelectionAdapter() {
- public void widgetSelected(SelectionEvent e) {
- Kernel32 kernel32 = Kernel32.INSTANCE;
- kernel32.SetLastError(0);
- User32 user32 = User32.INSTANCE;
- // 找到包含密码框的java窗体的handle
- HWND handle = new HWND(new Pointer(clientSite.handle));
- // 找到ActiveX的handle
- handle = user32.GetWindow(handle, new DWORD(User32.GW_CHILD));
- // 找到ActiveX中密码输入框的handle
- handle = user32.GetWindow(handle, new DWORD(User32.GW_CHILD));
- // 发送消息
- final WPARAM CHAR_BS = new WPARAM(0x08);
- final int WM_CHAR = 0x0102;
- LPARAM l = new LPARAM(0);
- user32.PostMessage(handle, WM_CHAR, CHAR_BS, l);
- int lastError = kernel32.GetLastError();
- if (lastError != 0) {
- System.out.println("last error = " + lastError);
- }
- }
- });
- MenuItem menuPostMessage = new MenuItem(menuFile, SWT.CASCADE);
- menuPostMessage.setText("Append a char '1'");
- menuPostMessage.addSelectionListener(new SelectionAdapter() {
- public void widgetSelected(SelectionEvent e) {
- Kernel32 kernel32 = Kernel32.INSTANCE;
- kernel32.SetLastError(0);
- User32 user32 = User32.INSTANCE;
- // 找到包含密码框的java窗体的handle
- HWND handle = new HWND(new Pointer(clientSite.handle));
- // 找到ActiveX的handle
- handle = user32.GetWindow(handle, new DWORD(User32.GW_CHILD));
- // 找到ActiveX中密码输入框的handle
- handle = user32.GetWindow(handle, new DWORD(User32.GW_CHILD));
- // 发送消息
- final int WM_CHAR = 0x0102;
- WPARAM w = new WPARAM('1');
- LPARAM l = new LPARAM(0);
- user32.PostMessage(handle, WM_CHAR, w, l);
- int lastError = kernel32.GetLastError();
- if (lastError != 0) {
- System.out.println("last error = " + lastError);
- }
- }
- });
- }
- }
OleFactory.java (附件里忘了+了)
- import java.util.HashMap;
- import java.util.Map;
- import org.eclipse.swt.SWT;
- import org.eclipse.swt.SWTError;
- import org.eclipse.swt.layout.FillLayout;
- import org.eclipse.swt.ole.win32.OLE;
- import org.eclipse.swt.ole.win32.OleAutomation;
- import org.eclipse.swt.ole.win32.OleClientSite;
- import org.eclipse.swt.ole.win32.OleFrame;
- import org.eclipse.swt.ole.win32.Variant;
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Shell;
- import com.sun.jna.Native;
- import com.sun.jna.Pointer;
- import com.sun.jna.platform.win32.Kernel32;
- import com.sun.jna.platform.win32.User32;
- import com.sun.jna.platform.win32.WinDef.DWORD;
- import com.sun.jna.platform.win32.WinDef.HWND;
- import com.sun.jna.platform.win32.WinDef.LPARAM;
- import com.sun.jna.platform.win32.WinDef.WPARAM;
- import com.sun.jna.platform.win32.WinUser;
- import com.sun.jna.win32.StdCallLibrary;
- import com.sun.jna.win32.W32APIOptions;
- public class OleFactory {
- public static void main(String[] args) {
- PasswordEncrypter encrypter = new PasswordEncrypter();
- encrypter.setOleFactory(OleFactory.getInstance());
- String clearPassword = "111111";
- String encryptedPassword = encrypter.encrypt(clearPassword);
- System.out.println("-------------------------------");
- System.out.println("clear password = [" + clearPassword + "]");
- System.out.println("encrypted password = [" + encryptedPassword + "]");
- clearPassword = "222222";
- encryptedPassword = encrypter.encrypt(clearPassword);
- System.out.println("-------------------------------");
- System.out.println("clear password = [" + clearPassword + "]");
- System.out.println("encrypted password = [" + encryptedPassword + "]");
- OleFactory.getInstance().unregistAll();
- }
- private Map<String, ComContainer> oleContainerMap = new HashMap<String, ComContainer>();
- private static OleFactory instance = null;
- private OleFactory() {
- };
- public final static OleFactory getInstance() {
- if (instance == null) {
- instance = new OleFactory();
- }
- return instance;
- }
- /**
- * NOTICE : when using the return object, pay attention about
- * synchonization.
- *
- * @param clsId
- * e.g. "Word.Document", "{11111111-2222-3333-4444-555555555555}"
- */
- public synchronized OleClientSite registAndGetOle(String progId) {
- ComContainer container = oleContainerMap.get(progId);
- if (container == null) {
- container = new ComContainer(progId);
- oleContainerMap.put(progId, container);
- }
- if (!container.isAlive()) {
- container.start();
- while (!container.isReady()) {
- try {
- container.join(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
- return container.getOleClientSite();
- }
- @SuppressWarnings("deprecation")
- public synchronized void unregistOle(String progId) {
- ComContainer container = oleContainerMap.get(progId);
- if (container != null) {
- if (container.isAlive()) {
- container.notifyStop();
- try {
- container.join(1000);
- } catch (InterruptedException e) {
- }
- if (container.isAlive()) {
- container.stop();
- }
- }
- oleContainerMap.remove(progId);
- }
- }
- public synchronized void unregistAll() {
- for (String progId : oleContainerMap.keySet()) {
- unregistOle(progId);
- }
- }
- public static class PasswordEncrypter {
- private final String progId = "{488A4255-3236-44B3-8F27-FA1AECAA8844}";
- private OleFactory oleFactory = null;
- public synchronized String encrypt(String password) {
- Kernel32 kernel32 = Kernel32.INSTANCE;
- kernel32.SetLastError(0);
- User32 user32 = User32.INSTANCE;
- OleClientSite clientSite = oleFactory.registAndGetOle(progId);
- // find the window handle of OleFrame
- HWND h = new HWND(new Pointer(clientSite.handle));
- // find the window handle of the ActiveX
- h = user32.GetWindow(h, new DWORD(User32.GW_CHILD));
- // find the window handle of the password input control
- h = user32.GetWindow(h, new DWORD(User32.GW_CHILD));
- // clear previous input first
- final char CHAR_BS = 0x08;
- WPARAM wParam = new WPARAM(CHAR_BS);
- LPARAM lParam = new LPARAM(1);
- OleAutomation ole = new OleAutomation(clientSite);
- int[] rgdispid = ole.getIDsOfNames(new String[] { "TextData" });
- Variant var = ole.getProperty(rgdispid[0]);
- while (OLE.VT_EMPTY != var.getType()) {
- MyUser32.INSTANCE
- .SendMessage(h, User32.WM_CHAR, wParam, lParam);
- var = ole.getProperty(rgdispid[0]);
- }
- // send the new password string
- for (char c : password.toCharArray()) {
- wParam = new WPARAM(c);
- int errorNo = 0;
- int tryTimes = 0;
- kernel32.SetLastError(0);
- do {
- MyUser32.INSTANCE.SendMessage(h, User32.WM_CHAR, wParam,
- lParam);
- tryTimes++;
- errorNo = kernel32.GetLastError();
- } while (errorNo != 0 && tryTimes < 3);
- if (errorNo != 0) {
- throw new RuntimeException("Could not complete the "
- + "password encoding. error code = " + errorNo);
- }
- }
- // get the encrypted password
- var = ole.getProperty(rgdispid[0]);
- if (OLE.VT_NULL == var.getType()) {
- return null;
- } else if (OLE.VT_EMPTY == var.getType()) {
- return "";
- }
- return var.getString();
- }
- public void setOleFactory(OleFactory oleFactory) {
- this.oleFactory = oleFactory;
- }
- }
- }
- /**
- * An container for ActiveX/COM components with windows UI.
- * For those without UI, U can also consider using Jacob etc.
- */
- class ComContainer extends Thread {
- private Display display = null;
- private Shell shell = null;
- private OleClientSite clientSite = null;
- private boolean stop = false;
- private String progId = null;
- private boolean ready = false;
- /**
- * @param clsId
- * e.g. "Word.Document", "{11111111-2222-3333-4444-555555555555}"
- */
- public ComContainer(String progId) {
- this.progId = progId;
- ready = false;
- stop = false;
- }
- public void run() {
- ready = false;
- stop = false;
- display = new Display();
- shell = new Shell(display);
- shell.setLayout(new FillLayout());
- try {
- OleFrame frame = new OleFrame(shell, SWT.NONE);
- clientSite = new OleClientSite(frame, SWT.NONE, progId);
- clientSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
- } catch (SWTError e) {
- e.printStackTrace();
- display.dispose();
- throw e;
- }
- stop = false;
- ready = true;
- shell.setSize(400, 300);
- // shell.open(); // You can uncomment this for an direct view
- // start to dispatch event
- while (!stop && !shell.isDisposed()) {
- if (!display.readAndDispatch()) {
- display.sleep();
- }
- }
- display.dispose();
- }
- public void notifyStop() {
- stop = true;
- }
- public OleClientSite getOleClientSite() {
- return clientSite;
- }
- public boolean isReady() {
- return ready;
- }
- }
- interface MyUser32 extends StdCallLibrary, WinUser {
- static MyUser32 INSTANCE = (MyUser32) Native.loadLibrary("user32",
- MyUser32.class, W32APIOptions.DEFAULT_OPTIONS);
- LRESULT SendMessage(HWND hWnd, int Msg, WPARAM wParam, LPARAM lParam);
- }
阅读(6239) | 评论(0) | 转发(0) |