Hello world!

欢迎使用 WordPress。这是您的第一篇日志。您可以编辑它或是删除它,然后开始写您自己的博客。

Posted in 未分类 | 1 Comment

搬家了

搬家到cnblogs了,这里暂时不打算继续更新了(虽然本来就很久没更新的说,face)。

就这样。

新blog地址:http://www.cnblogs.com/yonken/

Posted in 未分类 | 1 Comment

关于 CodeInjector 的开源

其实很久之前就看到有朋友说希望开源,可是因为很多原因,虽然想解释,但我这人很懒,也就没有回复。

不过刚刚下班回来,看到一个留言:

介于博主的不仗义,我这里贴出,od提供的源码。汇编和反汇编源码(GNU)。
下载地址: http://www.ollydbg.de/srcdescr.htm
如果没猜错的话,博主也是使用这个SDK了。

Bingo! 这位朋友猜的没错,正是用了OD的!

下面是自问自答时间:
Q:为什么不开源?
A:汗,因为代码写的很随便,有些恶心的BUG,代码简直不堪入目,所以为了避免恶心到别人。。。
  第二个原因是正如前面这位朋友说的那样,并没有任何含金量,只不过是用了人家的SDK罢了,更加没有所谓开源的理由了。

Q:当初弄这个的目的?
A:当时对注入代码和DLL感兴趣,有想法,就写了,就这么简单。

Q:不是说要支持变量定义吗?
A:确实是有这个打算,刚开始是想改SDK的代码,后来因为工作原因没有动手,再后来在公司正好有在做相关工作(解释执行C++代码),就开始想是不是干脆也弄个解释执行的,把解释引擎和脚本同时注入到目标进程里面然后解释执行脚本。再再后来。。face发现其实这是重复开发,何不干脆用现成的,现在已有很多优秀的这类代码可以实现了,比如 TinyCC,所以现在也是打算直接用人家的包装一下就OK了!不过这也是要遇上好的时间和心情才行啊。face

各位大哥,我不过是在自己的博客上胡言乱语罢了,可不是在给谁什么承诺哦,对吧?

最后,至于仗义不仗义,我不解释,博客就是给人满足自己的各种无聊的心理需求的平台罢了,没必要跟现实生活中那样维护自己甚至伪装自己(尽管依靠网络本身就是很好的伪装了)。

Posted in 胡言乱语 | 1 Comment

突然想测试一下递归的效率

前阵子在公司写了个递归函数,在公司自己的语言环境下run了一下,慢的受不了,程序简直就是停止响应了,于是在VC下测试时间,发现居然是0face

没办法,毕竟是解释执行的代码。

然后就想到好久没碰过的脚本,于是分别在AU3和AHK下写了个最简单的递归版fibonacci的脚本进行测试:

Autoit版本:

Func fibonacci($nn)
    If $nn = 0 Then Return
0
    If $nn <= 2 Then Return
1
    return fibonacci($nn-1) + fibonacci($nn-2
)
EndFunc

$testTimes =
20
$nn
=
23
$totalTime
=
0

$minTime
= -
1
$maxTime
= -
1

For
$ii = 0 To
$testTimes
    $begin = TimerInit
()
    $result = fibonacci($nn
)
    $elapsed = TimerDiff($begin
)
    $totalTime +=
$elapsed
    If $elapsed < $minTime Or $minTime = -1 Then $minTime =
$elapsed
    If $elapsed > $maxTime Then $maxTime =
$elapsed
Next

$averageTime = $totalTime /
$testTimes

MsgBox(0,
"fibonacci",
_
    "fibonacci(" & $nn & ") ="  & @TAB & $result        & @CRLF &
_
    "testTimes:"                & @TAB & $testTimes     & @CRLF &
_
    "Average time:"             & @TAB & $averageTime   & @CRLF &
_
    "minTime:"                  & @TAB & $minTime       & @CRLF &
_
    "maxTime:"                  & @TAB & $maxTime)


AutoHotkey版本:

fibonacci(nn)
- {
      if ( 0 = nn )
          return
0
      if ( nn <= 2
)
          return
1
      return fibonacci(nn-1) + fibonacci(nn-2
)
 
}
 
  nn =
23
  testTimes =
20
  totalTime =
0
  minTime = -
1
  maxTime = -
1
 
  Loop,
% testTimes
- {
      StartTime := A_TickCount
      result := fibonacci(nn
)
      elapsed := A_TickCount -
StartTime
      totalTime +=
elapsed
 
   
      If (elapsed < minTime Or minTime = -1
)
          minTime :=
elapsed
      If (elapsed > maxTime
)
          maxTime :=
elapsed
 
}
 
  averageTime := totalTime /
testTimes
 
  MsgBox, 0, fibonacci, fibonacci(%nn%) = %result%`ntestTimes = %testTimes%`nAverage:%averageTime%`nminTime:%minTime%`nmaxTime:%maxTime%



测试结果如下:

Autoit v3.3.0.0

fibonacci(23) = 28657
testTimes: 20
Average time: 522.569445485542
minTime: 466.840749850342
maxTime: 537.249004450691

AutoHotkey 1.0.48.03

fibonacci(23) = 28657
testTimes = 20
Average:668.750000
minTime:625
maxTime:719

测试平台:P4 3.06G

不过这也只是好玩而已,并没有太大的意义。

Posted in 脚本相关 | Leave a comment

在脚本中使用Send发送中文

[Updated:2008-12-29]
修改了AHK的代码
增加了一段能在新版AU3中使用的代码


最简单的方法其实是先把要发送的内容先保存到剪贴板中去,然后在要发送的时候“粘贴”一下(Send一个 Ctrl+V)即可。不过这样做有一些缺点:
1、由于使用了剪贴板,用户在 Send 的过程中将不能正常使用 Ctrl+C 和 Ctrl+V 等剪贴板相关的功能;
2、有可能会在还没执行完“粘贴”操作之前剪贴板的内容就被修改了,结果发送了别的内容。


当然还有别的方法,先引用一下下面的内容:

我们通过键盘只能够输入键盘上有的字符,其实,按住 ALT 键,然后在数字键盘上按表示要输入字符的十进制代码值的键,等完成输入后,释放 ALT 键还可以输入键盘上没有的字符呢。

如果键入的第一个数字是“0”,该值将被识别为当前输入区域设置中的代码点或字符值。例如,在当前的输入区域设置为“英语(美国)”时(代码页 1252:Windows Latin-1),按住 ALT 键,然后在数字键盘上键入“0163”将产生英镑符号 £ (U+00A3)。在当前输入区域是 "Russia" (代码页 1251:Windows Cyrillic),相同的键顺序会产生西里尔大写字母 JE (U+040 8)

而如果键入的第一位数是“1”到“9”的任意数,该值将被识别为系统 OEM 代码页中的代码点。根据在“控制面板”的“区域选项”中所指定的 Windows 系统区域设置,结果各有不同。例如,如果您的系统区域设置是“英语(美国)”,代码页为 437(MS-DOS 拉丁美洲),那么只要按住 ALT 键,然后在数字键盘上键入“163”,就可以输入 ú(U+00FA, 带重音符号的小写拉丁字母 U)。如果系统区域设置是“希腊语”(OEM 代码页 737 MS-DOS 希腊),相同序列将产生希腊语小写字母 MU (U+03BC)。

新建一个文本文件,输入“中文”这两个字并保存,然后用UltraEdit等十六进制编辑器打开并用十六进制视图显示,可看到如下内容:

00000000h: D6 D0 CE C4                                     ; 中文

可知中文这两个字的十六进制分别是 0xD6D0、0xCEC4(即十进制的54992、52932),那么如果要输入“中”字,则只要按住Alt键,逐个输入其十进制数字54992即可。
这样,要实现自己的 Send 函数就简单了:

AHK脚本:
; GBK是GB2312的扩展,是向下兼容的,因此GB2312中的汉字的编码与GBK中
; 汉字的相同。另外,GBK中还包含繁体字的编码,GBK中每个汉字仍然包含两
; 个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个字节的范围
; 是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。

#NoEnv
SetKeyDelay
,
20                 
; 如因速度过快导致发送不正常请尝试修改此行的延迟数值
SendMode InputThenPlay      
; 如因速度过快导致发送不正常请则注释此行或改为其它模式
SetWorkingDir %A_ScriptDir%

string1 :=
"简体中文字符发送测试"
string2 :=
"繁體中文字符發送測試"

F10
::
    Loop,
100
    {
        SendString( "Sending #" . A_Index . " " . string1
)
        Send, {Enter}
    }
Return

SendString( string
)
{
    Len := StrLen(string)  
; 得到字符串的长度,注意一个中文字符的长度是2,即占2个字节
    Keys := ""                  
; 将要发送的字符序列
    Index := 1                  
; 用于循环
    
Loop
    {
        IsUnicodeChar :=
false
        Code2 := 0                                             
; 字符2的ASCII码
        Code1 := Asc( SubStr(string, Index, 1) )    
; 得到第一个字符的ASCII值
        if(Code1 >= 129 && Code1 <= 254 && Index < Len)   
; 判断是否中文字符的第一个字符
        {
            Code2 := Asc( SubStr(string, Index+1, 1) )            
; 得到第二个字符的ASCII值
            if(Code2 >= 64 && Code2 <= 254)        
; 若条件成立则说明是中文字符
            {
                IsUnicodeChar :=
true
                Code1 <<= 8                                  
; 第一个字符应放到高8位上
                Code1 += Code2                              
; 第二个字符放在低8位上
            }
            ++Index
        }
        if( IsUnicodeChar
)
            Keys .= "{ASC " . Code1 .
"}"
       
else
        {
            Keys .= "{ASC 0" . Code1 . "}"                
; 如果非中文字符,则需要前缀一个0
            if( Code2 > 0
)
                Keys .= "{ASC 0" . Code2 .
"}"
        }
        ++Index
        if(Index > Len
)
            
Break
    }
    Send % Keys
}

SendByClipboard( string, BackupClipBoard = false
)
{
    if(BackupClipBoard
)
        ClipSaved :=
ClipboardAll
    ClipBoard := string
    Send ^v
    if(BackupClipBoard
)
    {
        Clipboard := ClipSaved
        ClipSaved
=
    }
}

///////////////////////////////////////////////////////////////////////////////

AU3脚本(3.2.4.0 之后的版本)
由于AutoIt自从版本3.2.4.0+开始已不再提供ANSI版本,因此再写个能在新版用的

测试版本:v3.3.0.0
在编写的过程中,一开始是打算使用 StringToBinary/Binary/DllStructSetData 来生成一个Ansi字符串方便处理的,但因为AutoIt存在将字符串截断的问题(这个问题也算是历史悠久了),因此不得不使用API来进行转换。
有意思的是,在AutoIt的更新日志里面却说这个问题已经解决了face


Fixed #92: DllStruct data truncated with char[]/wchar[].

最后还是要抱怨一下默认情况下AutoIt的 Send 函数速度实在是太慢了,好在AutoHotkey的速度很理想,尽管Send这种功能我本来也很少用 :)

HotKeySet("{F10}", "SendTest")

While
1
    Sleep(100)
WEnd

Func
SendTest()
    Local $string = "A中文字符串A"
    $begin = TimerInit()

    For $i = 1 To 10
        _Send( $string )
        Send("{Enter}")
    Next
    $dif = TimerDiff($begin)
    MsgBox(0,"Time passed", $dif)
EndFunc

; 函数: _Send
; 用途:发送字符串
; 参数:$string,待转换的字符串,既可以是字符串字面值常量也可以是一个指向包含
;                Unicode 字符数组的 DllStruct 元素的指针
;       $bSendKeys,是否发送字符串,为 false 时只返回待发送的 Keys(请参考返回
;                值的说明) 而不发送字符串
; 返回值:使用 Send 函数时传递给它的第一个参数(Keys),形如 {Asc nn1}{Asc nn2}
Func _Send( Const $string, $bSendKeys = true )
    Local $szKeys = ""                           ; 待发送的按键序列
    Local $nLen = StringLen($string)             ; 字符串的长度
    ; 字符串的 Unicode 编码数组
    Local $UnicodeStringASCIIArray = StringToASCIIArray( $string )
    ; 因须将 $string 转换为多字节版本,下面计算足够用以保存转换成后数据的空间大小    
    Local $nAnsiBufferSize = ($nLen+1) * 2               
    ; 用以保存转换后的结果
    Local $pAnsiStringStruct = DllStructCreate("ubyte[" & $nAnsiBufferSize & "]")
    ; 将 $string 转换为多字节版本
    Local $nBytesWritten = WideCharToMultiByte( $string, DllStructGetPtr($pAnsiStringStruct) )
    If $nBytesWritten <= 0 Then
        $pAnsiStringStruct = 0
        Return SetError(@error, 0, "")
    EndIf


    Local $AnsiIndex = 1  ; Ansi 字符串元素的索引
    Local $value          ; 要传给 Send 函数的数值,用以构成 {Asc $value}
    For $i = 0 To $nLen-1
        $value = DllStructGetData($pAnsiStringStruct, 1, $AnsiIndex)
        If $UnicodeStringASCIIArray[$i] > 255 Then  ; 大于255的字符说明是Unicode字符
            $AnsiIndex += 1
            $value = $value * 256 + DllStructGetData($pAnsiStringStruct, 1, $AnsiIndex)
        ElseIf $value > 0 Then
            $value = "0" & $value
        EndIf
        $szKeys &= "{Asc " & $value & "}"
        $AnsiIndex += 1
    Next
    If $bSendKeys Then Send($szKeys)
    $pAnsiStringStruct =
0

    Return $szKeys
EndFunc
   ;==>_Send

Func SendByClipboard( Const $string, $BackupClipBoard = false )
    If $BackupClipBoard Then
        Local $bak = ClipGet()
    EndIf
    ClipPut($string)
    Send("^v")
    If $BackupClipBoard Then ClipPut($bak)
EndFunc

; 函数: WideCharToMultiByte
; 用途:将 Unicode 字符串转换为多字节字符串
; 参数:$UnicodeString,待转换的字符串,既可以是字符串字面值常量也可以是一个指
;                向包含 Unicode 字符数组的 DllStruct 元素的指针
;       $pMultiByte,用以保存转换结果的地址,指向一个char/byte数组的 DllStruct
;                元素的指针
;       $iCodePage,代码页
; 返回值:写入到 $pMultiByte的字节数
Func WideCharToMultiByte($UnicodeString, $pMultiByte, $iCodePage = 0)
    Local $aResult, $ParamType = "wstr"
    If IsPtr($UnicodeString) Then $ParamType = "ptr"
   
    $aResult = DllCall("Kernel32.dll", "int", "WideCharToMultiByte", "int", $iCodePage, "int", 0, _
            $ParamType, $UnicodeString, "int", -1, "int", 0, "int", 0, "int", 0, "int", 0)
    If @error Then Return SetError(@error, 0, 0)
    $aResult = DllCall("Kernel32.dll", "int", "WideCharToMultiByte", "int", $iCodePage, "int", 0, _
            $ParamType, $UnicodeString, "int", -1, "ptr", $pMultiByte, "int", $aResult[0], "int", 0, "int", 0)
    If @error Then Return SetError(@error, 1, 0)
    Return $aResult[0]
EndFunc
  ;==>WideCharToMultiByte


///////////////////////////////////////////////////////////////////////////////

AU3脚本(3.2.4.0 之前的版本)
(注意,最新版本(3.2.4.0+)已不再提供ANSI版本!因此请注意你的AutoIt版本):
#cs
运行脚本时需用 AutoIt3A.exe
将 AutoIt 目录下的AutoIt3A.exe重命名为AutoIt3.exe即可(建议先备份AutoIt3.exe)
编译脚本时需用 Aut2exeA.exe
#ce

Run
("notepad"
)
WinWaitActive("[CLASS:Notepad]"
)

_SendRaw("简体中文And繁體中文")

Func _SendRaw($Keys
)
    Local $KeysInUnicode =
""
    Local $len = StringLen($Keys
)
    Local
$char1
    Local
$code1
    Local
$char2
    Local
$code2
    Local $index =
1
    While
True
        $code2 =
0
        $char1 = StringMid($Keys, $index,
1)
        $code1 = Asc($char1)
        If $code1 >= 129 And $code1 <= 254 And $index < $len
Then
            $char2 = StringMid($Keys, $index+1,
1)
            $code2 = Asc($char2)
            If $code2 >= 64 And $code2 <= 254
Then
                $code1 *=
256
                $code1 +=
$code2
           
EndIf
            $index +=
1
       
EndIf
        If $code1 <= 255 Then $code1 = "0" &
$code1
        $KeysInUnicode &= "{ASC " & $code1 &
"}"
        If $code2 > 0 And $code2 < 64
Then
            $code2 = "0" &
$code2
            $KeysInUnicode &= "{ASC " & $code2 &
"}"
       
EndIf
        $index +=
1
        If $index > $len Then
ExitLoop
   
WEnd
    Send($KeysInUnicode
)
EndFunc

Posted in 脚本相关 | Tagged | 15 Comments

在VC2005下编译AutoHotkey

    关于在VC2005下编译AutoHotkey的方法其实在AHK的官方论坛上已经有相关帖子(点击此处查看)了,不过如果是在中文系统上编译还需要进行一点修改,由于可能会有人需要这方面的信息,因此以版本 1.0.47.06 为例说明一下,部分内容从上面提到的帖子中翻译而来。

AutoHotkey 源代码下载地址:
http://www.autohotkey.com/download/AutoHotkey104706_source.exe


1、下载源代码并解压,打开项目文件AutoHotkey.sln,由于AutoHotkey的源代码是在VC2003下建立的,因此需要进行转换;

2、转换完毕后直接编译,遇到一堆警告(主要都是叫你使用字符串函数的”安全“版本)和几个错误,到第一个错误的地方去看吧,提示是在文件 script.cpp 的第 1130 行处出错(主要是代码页产生的问题),该行内容如下:

   if (strcmp(buf, "锘?))  // UTF-8 BOM marker is NOT present.

   可看到上面这个字符串显示不正确,用UltraEdit等十六进制编辑工具打开 script.cpp 文件,到 1130 行并切换到十六进制显示方式,可知该字符串的十六进制表示是 EF BB BF (00),那么回到VC把这行改成如下所示即可:

   if (strcmp(buf, "xEFxBBxBF"))  // UTF-8 BOM marker is NOT present.

3、打开菜单 项目->AutoHotkey属性

   a) 在 配置属性->C/C++->常规
      把 将警告视为错误 设为

   b) 在 配置属性->C/C++->预编译头
      把 创建/使用预编译头 设为 创建预编译头(/Yc)

   c) 在 配置属性->C/C++->高级
      把 调用约定 改为其它项目后再改回 __cdecl (/Gd)

   d) 在 配置属性->C/C++->高级
      把 省略默认的库名称 设为 是(/Zl)

   e) 在 配置属性->链接器->输入
      把 
忽略特定库 中的 LibCMT; 删除

   f) 在 配置属性->链接器->优化
      把 
链接时间代码生成 设为 使用链接时间代码生成(/ltcg)

4、在VC的解决方案资源管理器中找到 AutoHotkey.rc 文件并选择 查看代码,找到
   CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST             "AutoHotkey.exe.manifest"
  并注释该行
  (该行代码的作用主要是让程序具有XP style,否则程序界面将以经典样式显示)

5、如果是Debug版本则无需做更多修改;如果是Release版本,需到 http://upx.sourceforge.net/ 下载UPX,把upx.exe放到项目所在文件夹(即AutoHotkey.sln的同一目录)下,目的是在编译成功后自动使用UPX压缩生成的可执行文件,当然也可以去掉这一步:在 项目->AutoHotkey属性 中,在 配置属性->生成事件->生成后事件 下把 命令行 中的内容 清空

6、开始编译,成功后VC将显示下述内容(Release版):

已完成传递 2
正在嵌入清单...
正在执行生成后事件...
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2008
UPX 3.03w       Markus Oberhumer, Laszlo Molnar & John Reiser   Apr 27th 2008
        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
    536576 ->    254976   47.52%    win32/pe     AutoHotkey.exe
Packed 1 file.
生成日志保存在“file://e:Code4FunAutoHotkey104706_sourceReleaseBuildLog.htm”
AutoHotkey - 0 个错误,16 个警告
========== 生成: 1 已成功, 0 已失败, 1 最新, 0 已跳过 ==========


  

Posted in 未分类 | Tagged , , , | 3 Comments

代码/DLL注入工具 [CodeInjector v1.2] 小修正


今晚既然有空就一并将上次发现的一些问题给解决掉吧,更新如下:

1)使用多线程,刚开始打开进程列表对话框时不会停顿了;

2)修正了在进程列表排序后选中某个进程时DLL更新错误的BUG;

3)修正了在进程列表排序后使用窗口/进程查找工具时定位进程项目错误的BUG;


下载地址:

下载地址1   备用下载地址


MD5: 1367D3319D2034957FEF3A9C0DBAD9FF

Posted in 我的作品 | 13 Comments

AHK-系统托盘/任务栏图标信息获取及控制工具 [ShellTrayTaskBarInfo v1.0]

早在两个月前就曾有位朋友发邮件给我提到操作系统托盘(Shell Tray)的问题,当时他说目的如下:

1、获取系统托盘各程序信息
2、对系统托盘程序发送左键单击、双击及右键单击事件
3、能否用AHK实现,或者AU3呢?

现在总算有时间动手,用AHK实现,既然任务栏(Taskbar)也是个Toolbar,那干脆就把任务栏的部分也一并实现了。

我实现的例子程序可以移动托盘/任务栏的图标位置、模拟鼠标单击、双击等,至于要增加/删除/隐藏按钮等功能应该很少有需要所以没加入,如果要实现的话也是很简单的,甚至只需要直接调用 ToolbarWrapper.ahk 中的相关函数就可以实现了。

需要注意的是,此脚本可能并不支持XP以前的操作系统。

如果你需要使用我的代码,请看下面的说明部分。



[截图/Screenshot]

点击放大


[说明/Remarks]

1) 脚本文件:
    ┌ ShellTrayTaskBarInfo.ahk   [例子]
    ├ ShellTrayHelper.ahk        [实现托盘的部分]
    ├ TaskBarHelper.ahk          [实现任务栏的部分]
    └ [Utils]
        ├ ToolbarWrapper.ahk     [工具栏通用函数集合]
        ├ Kernel32.ahk           [API、常量等]
        ├ User32.ahk             [API、常量等]
        └ Utils.ahk              [一些工具函数]

 如果需要在自己的脚本中使用这些代码,只需要#Include ShellTrayHelper.ahk/TaskBarHelper.ahk/ToolbarWrapper.ahk就可以了。

2) 下载压缩包(地址见文章底部),解压后运行 ShellTrayTaskBarInfo.ahk 即可;

3) 在显示托盘图标信息时,在ListView的某一项上点击右键或双击可模拟相应的鼠标操作;

4) 为减少脚本打开explorer进程、申请内存和释放内存的操作次数,我在脚本中通过保存相关数据而避免了,但同时也使得脚本复杂了些,如果觉得多此一举可去除和修改 ToolbarWrapper.ahk 的相关代码。

5) 其他请自行阅读代码,如有不明之处请阅读 [参考资料/References] 部分列出的文章。

[其他/Others]

2009/01/06:修复了Utils.ahk中的一个小BUG,原本第 89 行中的
              VarSetCapacity( pWideCharBuffer, nRequiredSize, 0 )
            应该改为
              VarSetCapacity( pWideCharBuffer, nRequiredSize<<1, 0 )
            这个修正并没有更新到下载点的文件上,请自行修正。

2008/12/14:修复了例子代码中的几个小BUG,即都在脚本 ShellTrayTaskBarInfo.ahk 中,在此贴出修正后的 ShellTrayTaskBarInfo.ahk 的代码。






; AutoHotkey Version: 1.0.47.06
; Platform:       WinXP
; Author:         Yonken <yonken@163.com>
; Last updated: 2008-12-12
; Copyright:   
;       You are allowed to include the source code in your own product(in any form) when
;   your product is released in binary form.
;       You are allowed to copy/modify/distribute the code in any way you want except
;   you can NOT modify/remove the copyright details at the top of each script file.

; References:
;   http://blog.csdn.net/hailongchang/archive/2008/12/05/3454569.aspx
;   http://blog.csdn.net/hailongchang/archive/2008/12/10/3490353.aspx
;   http://www.codeproject.com/KB/shell/taskbarsorter.aspx

#
NoEnv
#
NoTrayIcon
#SingleInstance
ignore
SetWorkingDir %A_ScriptDir%

#Include ShellTrayHelper.ahk
#Include TaskBarHelper.ahk

if A_OSVersion in WIN_NT4,WIN_95,WIN_98,WIN_ME
{
    MsgBox This script only works under Windows 2000/XP or later
   
ExitApp
}

OnExit, MyExit

g_szAppName :=
"ShellTrayTaskBarInfo"
g_szAppVersion :=
"1.1"

; **** Do NOT modify following variable when script is running! ****
g_szShellTrayName   :=
"ShellTray"
g_szTaskBarName :=
"TaskBar"

g_szToolbarName_1 := g_szShellTrayName 
; To visit current selected info, use g_szToolbarName_%g_nSelectedInfo%
g_szToolbarName_2 := g_szTaskBarName

; Main window

Gui, +Resize +MinSize850x95
Gui, Add, Button, gBtnRefresh, Refresh
Gui, Add, Button, xp+150 yp gSendLeftClick, SendLeftClick
Gui, Add, Button, xp+150 yp gMoveLeft, << MoveLeft
Gui, Add, Button, xp+100 yp gMoveRight, MoveRight
>>
Gui
, Add, GroupBox, xp+100 yp-5 w220 h30,
Gui, Add, Radio, xp+10 yp+10 vg_nSelectedInfo gSwitchInfoView Checked, ShellTrayInfo
Gui, Add, Radio, xp+120 yp gSwitchInfoView, TaskBarInfo
Gui, Add, Checkbox, xp+100 yp gSwitchShowHiddenItems vg_bShowHiddenItems, ShowHiddenItems

Gui, Add,
ListView
    , xp-730 yp+30 w875 h350 cBlue Grid NoSortHdr -Multi -LV0x10 AltSubmit vInfoListView gInfoListViewEvent
    , Icon|Tips|Process|Window
   
g_ImageListID := IL_Create(10
)
LV_SetImageList
(g_ImageListID
)

Gui
, Show, w900 h400, %g_szAppName% %g_szAppVersion% by Yonken [http://yonken.blogcn.com
]
Gosub
, SwitchInfoView
Return

GuiEscape
:
GuiClose
:
ExitApp

GuiSize
:
    if( A_EventInfo = 1
)
       
return
    GuiControl, Move, InfoListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - 50
)
Return

MyExit: 
; Do the cleanup stuffs on exit
    TW_Cleanup(g_szShellTrayName
)
    TW_Cleanup(g_szTaskBarName
)
   
ExitApp
Return

SwitchInfoView
:
    Gui, Submit,
NoHide
    if(g_nSelectedInfo = 1) 
; that is ShellTrayInfo
    {
        GuiControl, Show, SendLeftClick
    }
    else   
; that is TaskBarInfo
    {
        GuiControl, Hide, SendLeftClick
    }
    GoSub, BtnRefresh
Return

SwitchShowHiddenItems
:
    Gui, Submit,
NoHide
    GoSub, BtnRefresh
Return

BtnRefresh
:
    GuiControl, Disable, Refresh
    GuiControl, Disable, SendLeftClick
    GuiControl, Disable, << MoveLeft
    GuiControl, Disable, MoveRight
>>
    GuiControl, Disable, ShellTrayInfo
    GuiControl, Disable, TaskBarInfo
   
    pUpdateFunction := % "Update" . g_szToolbarName_%g_nSelectedInfo% .
"Info"
    %pUpdateFunction%
()
   
    GuiControl, Enable, Refresh
    GuiControl, Enable, SendLeftClick
    GuiControl, Enable, << MoveLeft
    GuiControl, Enable, MoveRight
>>
    GuiControl, Enable, ShellTrayInfo
    GuiControl, Enable, TaskBarInfo
Return

SendLeftClick
:
    nSelectedItemIndex := LV_GetNext
()
    if(nSelectedItemIndex
)
        LV_GetText(nSelectedBtnIndex, nSelectedItemIndex, 1
)
   
else
       
return
    if( GetShellTrayToolbarTrayDataByIndex( g_szShellTrayName, nSelectedBtnIndex, pTRAYDATA )
)
        LeftClickShellTrayToolbarButton(pTRAYDATA
)
Return

MoveLeft
:
    nSelectedItemIndex := LV_GetNext
()
    if(nSelectedItemIndex > 1)  
; 1-based
        LV_GetText(nSelectedBtnIndex, nSelectedItemIndex, 1
)
   
else
       
return
    if( nSelectedBtnIndex > 0 )  
; 0-based
    {
        LV_GetText(nPriorSelectedBtnIndex, nSelectedItemIndex-1, 1
)
        TW_MoveToolbarButton( g_szToolbarName_%g_nSelectedInfo%, nSelectedBtnIndex, nPriorSelectedBtnIndex
)
        GoSub, BtnRefresh
        LV_Modify(nSelectedItemIndex-1, "Select"
)
    }
Return

MoveRight
:
    nSelectedItemIndex := LV_GetNext
()
    if( nSelectedItemIndex < LV_GetCount() )  
; 1-based
        LV_GetText(nSelectedBtnIndex, nSelectedItemIndex, 1
)
   
else
       
return
    if( nSelectedBtnIndex < TW_GetToolbarButtonCount(g_szToolbarName_%g_nSelectedInfo%)-1
)
    {
        LV_GetText(nPostSelectedBtnIndex, nSelectedItemIndex+1, 1
)
        TW_MoveToolbarButton( g_szToolbarName_%g_nSelectedInfo%, nSelectedBtnIndex, nPostSelectedBtnIndex
)
        GoSub, BtnRefresh
        LV_Modify(nSelectedItemIndex+1, "Select"
)
    }
Return

InfoListViewEvent
:
    nItemIndex := LV_GetNext
()
    if(nItemIndex <= 0 || g_nSelectedInfo != 1 || nItemIndex > LV_GetCount()
)
       
return
    LV_GetText(nBtnIndex, nItemIndex, 1
)
    if ( A_GuiEvent = "DoubleClick"
)
    {
        if( GetShellTrayToolbarTrayDataByIndex( g_szShellTrayName, nBtnIndex, pTRAYDATA )
)
            LeftDbClickShellTrayToolbarButton(pTRAYDATA
)
    }
    else if( A_GuiEvent = "RightClick"
)
    {
        if( GetShellTrayToolbarTrayDataByIndex( g_szShellTrayName, nBtnIndex, pTRAYDATA )
)
            RightClickShellTrayToolbarButton(pTRAYDATA
)
    }
Return

UpdateShellTrayInfo
()
{
    Global g_ImageListID, g_szShellTrayName, InfoListView, g_bShowHiddenItems
    nRtn :=
0
    GuiControl, -Redraw, InfoListView
    LV_Delete
()
    nButtonCount := TW_GetToolbarButtonCount( g_szShellTrayName
)
    Loop, % nButtonCount
    {
        if( !TW_GetToolbarButton( g_szShellTrayName, A_Index-1, pTBBUTTON )
)
        {
            OutputDebug, GetShellTrayToolbarButton failed!
        }
        else if( !GetShellTrayToolbarTrayDataByBtn( pTBBUTTON, pTRAYDATA )
)
        {
            OutputDebug, GetShellTrayToolbarTrayDataByBtn failed!
        }
       
else
        {
            hIcon := _TD_hIcon(pTRAYDATA
)
           
;szTips := _TD_szTips(pTRAYDATA)
            if( !TW_GetToolbarButtonText(g_szShellTrayName, _TB_idCommand(pTBBUTTON), szTips)
)
                szTips :=
""
            szProcess := _TD_szExePath(pTRAYDATA
)
            hWnd := _TD_hWnd(pTRAYDATA
)
            nProcessId := GetWindowProcessID(hWnd
)
            if( IsTBHidden(pTBBUTTON)
)
            {
                if(g_bShowHiddenItems
)
                    szTips .=
"[Hidden]"
               
else
                   
continue
            }
            SetFormat, integer, hex
            hWnd +=
0
            SetFormat, integer, d
            DetectHiddenWindows,
on
            WinGetTitle, szWndTitle, ahk_id %hWnd%
            DetectHiddenWindows,
off
            nIconNumber := DllCall("ImageList_ReplaceIcon", "UInt", g_ImageListID, "int", -1, "UInt", hIcon) +
1
            LV_Add("Icon" . nIconNumber, A_Index-1, szTips, "[" . nProcessId . "] " . szProcess, "[" . hWnd . "] " . szWndTitle
)
        }
    }
   
    GuiControl, +Redraw, InfoListView
    LV_ModifyCol
()
    return nRtn
}

UpdateTaskBarInfo
()
{
    Global g_ImageListID, g_szTaskBarName, InfoListView, g_bShowHiddenItems
    nRtn :=
0
    GuiControl, -Redraw, InfoListView
    LV_Delete
()
    nButtonCount := TW_GetToolbarButtonCount( g_szTaskBarName
)
    Loop, % nButtonCount
    {
        if( !TW_GetToolbarButton( g_szTaskBarName, A_Index-1, pTBBUTTON )
)
        {
            OutputDebug, GetTaskBarToolbarButton failed!
        }
       
else
        {
            hWnd :=
0
            hIcon :=
0
            nProcessId := -
1
            nIconNumber :=
0
            szProcess :=
""
            szWndTitle :=
""
           
            hWnd := GetTaskBarButtonBuddyWindowHandle(g_szTaskBarName, pTBBUTTON
)
           
            if(!hWnd && !g_bShowHiddenItems
)
               
continue
           
            if( !TW_GetToolbarButtonText(g_szTaskBarName, _TB_idCommand(pTBBUTTON), szTips)
)
                szTips :=
""
           
            if(hWnd != 0
)
            {
                hIcon := GetWindowHICON( hWnd
)

                if( IsTBHidden(pTBBUTTON)
)
                    szTips .=
" [Hidden]"
                WinGet, szProcess, ProcessName, ahk_id %hWnd%
                nProcessId := GetWindowProcessID(hWnd
)
               
                DetectHiddenWindows,
on
                WinGetTitle, szWndTitle, ahk_id %hWnd%
                DetectHiddenWindows,
off
               
                SetFormat, integer, hex
                hWnd +=
0
                SetFormat, integer, d
               
                if(hIcon != 0
)
                    nIconNumber := DllCall("ImageList_ReplaceIcon", "UInt", g_ImageListID, "int", -1, "UInt", hIcon) +
1
            }

            if(hWnd != 0
)
                LV_Add(hIcon ? "Icon" . nIconNumber : "Icon999999", A_Index-1, szTips, "[" . nProcessId . "] " . szProcess, "[" . hWnd . "] " . szWndTitle
)
           
else
                LV_Add("Icon999999", A_Index-1, szTips, "-", "-"
)
        }
    }
   
    GuiControl, +Redraw, InfoListView
    LV_ModifyCol
()
    return nRtn
}




[下载/Download]

1) 已编译的可执行文件   备用地址2(纳米盘)

MD5: 27AE21CD19B96F9C5E3DB582F3D60EA7

2) 打包的脚本(Zip)      备用地址2(纳米盘)


[参考资料/References]

1) 隐藏Windows系统托盘图标 
   http://blog.csdn.net/hailongchang/archive/2008/12/05/3454569.aspx

2) 隐藏Windows系统托盘图标(改进版) 
   http://blog.csdn.net/hailongchang/archive/2008/12/10/3490353.aspx

3) A tool to order the window buttons in your taskbar 
   http://www.codeproject.com/KB/shell/taskbarsorter.aspx

4) Extract Informations about TrayIcons 
   http://www.autohotkey.com/forum/topic17314.html

#######################################################################
                    转载请注明来源
               http://yonken.blogcn.com
#######################################################################
Posted in 脚本相关 | Tagged , , , | 6 Comments

Just wanna go home

There's nothing more than I can say.

Posted in 影音分享 | 2 Comments

代码/DLL注入工具 [CodeInjector v1.1]

[注意:这篇文章不是讲脚本的]

这是一个用来向指定进程注入代码/DLL的小工具,简单点说就是让某个进程执行你想让它执行的指令,或是让这个进程加载你/别人写的DLL模块,知道plugin的人应该很容易了解这是什么意思,暂时来说使用这个工具的人需要了解一定的汇编语言知识和Windows的进程/DLL机制。

这个小工具其实是2月份的时候就写了一半了,虽然并没能完成我当初想要实现的全部功能,却因为各种原因也没办法继续写下去了,但毕竟算是有点小实用性的功能出来了,就在广海论坛上发布过,当时还算挺受欢迎的。后来经过断断续续的修改,觉得也发布出来让有需要的人用一下。

主要是有了下面的一些变化:

[-] 把反汇编引擎的DLL去掉,直接整合到主程序中;
[+] 增加了DLL的注入/卸载等功能;
[*] 在对进程列表进行排序的时候,不再重新遍历进程,速度正常了,不再像之前那样要卡一下。

开发工具:Microsoft Visual Studio 6.0

先看看主界面:

                              主窗口(图一)

1


了解的人看了上图一眼应该就很容易知道怎么用了,但为了尽可能让更多的人了解,还是以一个实例来说一下吧!

实例目标:Windows自带的计算器(Calc.exe)
实例任务:让计算器自己弹出一个对话框,标题是"Test",内容是"Hello!"

实例分析:

[Q] 怎么弹出对话框?
[A] 弹出对话框需要调用API(可理解为操作系统提供给我们使用的函数/代码)MessageBox,其原型为:
int MessageBox(      

    HWND hWnd,           // 父窗口的句柄
    LPCTSTR lpText,      // 对话框的正文
    LPCTSTR lpCaption,   // 对话框的标题
    UINT uType           // 对话框的类型
);


    其中hWnd和uType我们暂时不用管是什么意思,只需要知道hWnd我们传个0给它就好了,而uType倒可以随便传个数字看看结果有什么不一样,另外两个参数想必也毋庸多说了吧。

    在这个任务中,如果用的是C/C++,我们应该这样调用:
    MessageBox(0, "Hello!", "Test", 123);

    但我们在CodeInjector中用的是纯汇编,要调用函数就需要类似这样的代码:

    push 参数2
    push 参数1
    call 函数地址


    但这里首先遇到了个问题:CodeInjector暂时还不支持定义变量/标号/过程等!也就是说,我们要的"Hello"和"Test"要另外想办法制造出来。我想到的办法是利用堆栈,我们先来看看"Hello"和"Test"在内存中应该是怎么的一个样子:
   
    54 65 73 74 00 48 65 6C 6C 6F 21 00  ==> Test Hello!
   
    这是这两个字符串(刚好12个字节)连在一起存放的情况,左侧是每个字符的ASCII码(十六进制),在C/C++中字符串是以0作为结束标志的。
    好了,我们想象一下它们在堆栈中的存放情况:
    
   
    54 65 73 74 | Test   <- esp,栈顶
    00 48 65 6C |  Hel
    6C 6F 21 00 | lo!


    如果我们紧接着就开始把参数压栈的话,那接下来堆栈的内容应该是这样的:

    uType
    lpCaption  -> esp
    lpText     -> esp+5
    hWnd


[Q] 怎么解决MessageBox的地址问题
[A] 利用调试器即可,此略。


实例步骤:

一、运行计算器

二、运行CodeInjector(点此下载

三、点击主窗口(见图一)左上方的按钮“选择目标进程”,在弹出窗口(见下图)上方的进程列表中选中计算器的进程并点击“确定”按钮:


                              (图二)



2


四、利用调试器或其它方法确定MessageBoxA的地址,假设为0x77D507EA(注意,这个值因系统而异);

五、回到主窗口,在中间的编辑框中输入以下代码:
    ; 54 65 73 74 00 48 65 6C 6C 6F 21 00  ==> Test Hello!
    ; Stack should be the following:
    ;   54 65 73 74 | Test   <- esp
    ;   00 48 65 6C |  Hel
    ;   6C 6F 21 00 | lo!
    ;   uType
    ;   lpCaption  -> esp
    ;   lpText     -> esp+5
    ;   hWnd

    push 0x00216F6C
    push
0x6C654800
    push
0x74736554

    push eax            
; save eax
    mov eax, esp
    add eax, 4          
; eax -> lpCaption

    push 0x00010040  ; uType
    push eax            ; lpCaption
    add eax, 5
    push eax            
; lpText
    push 0                ; hWnd
    call 0x77D507EA    ; MessageBoxA 注意,这个地址因系统而异

    pop eax              ; restore eax
    add esp, 0xC


六、点击主窗口上的“CreateRemoteThread”按钮。

实例结果:

    在点击“CreateRemoteThread”按钮后,会发现弹出一个对话框,如下图所示:

                              (图三)


3


    该对话框的标题和内容完全如目标一致,而且注意它的图标,跟计算器的一样,说明两者属于同一进程,任务成功。



    至于DLL注入的部分因为简单在此就不多做介绍了。

    关于注入代码的部分,本来我的计划是不用汇编,而是以一种能实现语言基本功能的“脚本”的方式,比如支持变量等,但因时间关系暂时还没办法做,有机会再说吧。

   ----------------------------------------------------------------
   转载请注明来自 http://yonken.blogcn.com

   CodeInjector下载:点击此处

   备用下载地址:http://www.namipan.com/d/7cf9f3fee75511432cffcafba055d24ae5e3fdd000de0200

   MD5: C49999C3E3B2E1DFA7EFF71BDB574B44
   ----------------------------------------------------------------

Posted in 我的作品 | Tagged , , , | 7 Comments