已经在大数字做了三年的windows C++开发了,坦白的讲,自己现在还是个小码农。深深的感到自己是个loser。如今,大家回家后鲜有打开电脑玩电脑的人,与09年我刚
上大学那会儿乃至13年刚入职的时候相比,堪称沧海桑田~互联网节奏太快了,windows终端目测已经沦陷,转瞬间就变成了移动端的天下。想起之前学习汇编,windows PE
文件,hook,线程注入等各种windows技能,对新技术的嗤之以鼻,如今对自己感到了呵呵。期间自己学过了PHP,JS,甚至安卓SDK NDK。学了不实践,两天忘光光。作为一个小码农,如今感到一丝彷徨迷茫,竟不知未来何去何从。
经过自己两天辗转反折的思考,感觉自己应该学习点服务端的知识,这个方面好友早就提醒过我多次,之前的我竟然执迷不悟。
我们部门的服务端开发语言百花齐放,lua,PHP,python,GO,四大阵营,这个也归结于领导的包容并收。听人说GO效率要比C\C++高,我听到了差点没笑掉大牙。但我深
深的知道,GO是个很牛逼的东西。决定在业余时间探索一下这个东西。 GO大道至简,开发环境搭建也就是解压缩,配置环境变量两个步骤而已。对了据说他吸收了各种语言的优点,摒弃了各种语言的缺点。到底是不是这么回事呢?我们来一点点探索吧~
系统变量名:
GOROOT
值:
Go的安装位置
系统变量名:
Path
追加值:
;%GOROOT%\bin
开发环境安装包在此 https://yunpan.cn/cRzWuKqjn9MIV 访问密码 a41e。
cmd 输入go 打印出如下一大堆信息,那么恭喜你,环境搭建成功了。然后让我们开始写自己的第一个GO程序吧~
package main
import "fmt"
func main() {
fmt.Printf("HelloWorld!")
}
代码注意:
func main(){
不可以写成
func main()
{
这个不仅仅是代码规范,Go为了统一编码风格的语法。
保存文件名为 gofirst.go
编译 go build gofirst.go
这个时候你会在gofirst.go目录下发现多了一个文件
拖入cmd黑框框执行,。
唔?生成的文件竟然有1942KB这么大!!!为啥子文件会这么大?难道Go会不再沿用windows PE结构?答案是否定的。
UE看了下Go交叉编译器生成的二进制文件,标准的win PE文件,很显然,代码段和资源段增加了不少内容。瑕不掩瑜,这可能是谷歌为了解决某种问题不得不这么做的吧。
IDA看了看,显然,为了输出一个hello world Go在初始化的时候做了不少工作。
没错,至少在输出Hello World方面。GO语言应该会比C语言慢个几十倍。 但它不是生来输出Hello World的。另外他是一种编译型语言,而且生成windows的标准WinPE文件。同理 *nix的标准执行文件。我们有理由相信,在大型项目上,抛开内存垃圾回收机制不讲,(语言自动管理垃圾回收机制,势必会对速度有一丁点影响)Go完全有理由媲美C、C++,还会大大降低开发的难度,我们有好多理由去好好了解下这么语言。
为了给大家展示一下Go语言媲美C语言的能力,我们写一个Go语言的 Windows MessBox程序。代码如下,唔~第一天写go程序,这段代码是copy自网络哦。为的是证明C能做到的,GO同样能做到,效率还不会太低哦。
package main
import (
"syscall"
"unsafe"
"fmt"
)
func abort(funcname string, err int) {
panic(funcname + " failed: " + syscall.Errno(err).Error())
}
var (
kernel32, _ = syscall.LoadLibrary("kernel32.dll")
getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
user32, _ = syscall.LoadLibrary("user32.dll")
messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
)
const (
MB_OK = 0x00000000
MB_OKCANCEL = 0x00000001
MB_ABORTRETRYIGNORE = 0x00000002
MB_YESNOCANCEL = 0x00000003
MB_YESNO = 0x00000004
MB_RETRYCANCEL = 0x00000005
MB_CANCELTRYCONTINUE = 0x00000006
MB_ICONHAND = 0x00000010
MB_ICONQUESTION = 0x00000020
MB_ICONEXCLAMATION = 0x00000030
MB_ICONASTERISK = 0x00000040
MB_USERICON = 0x00000080
MB_ICONWARNING = MB_ICONEXCLAMATION
MB_ICONERROR = MB_ICONHAND
MB_ICONINFORMATION = MB_ICONASTERISK
MB_ICONSTOP = MB_ICONHAND
MB_DEFBUTTON1 = 0x00000000
MB_DEFBUTTON2 = 0x00000100
MB_DEFBUTTON3 = 0x00000200
MB_DEFBUTTON4 = 0x00000300
)
func MessageBox(caption, text string, style uintptr) (result int) {
// var hwnd HWND
ret, _, callErr := syscall.Syscall6(uintptr(messageBox), 4,
0, // HWND
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), // Text
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), // Caption
style, // type
0,
0)
if callErr != 0 {
abort("Call MessageBox", int(callErr))
}
result = int(ret)
return
}
func main() {
defer syscall.FreeLibrary(kernel32)
defer syscall.FreeLibrary(user32)
fmt.Printf("Retern: %d\n", MessageBox("Done Title", "This test is Done.", MB_YESNOCANCEL))
}
func init() {
fmt.Print("Starting Up\n")
}
来来来,保存为messagebox.go
执行命令go build messagebox.go
同样文件不小,也许是包含了调试信息? 这个我们之后再进行探索。运行结果如下
注意,我们调用了
kernel32, _ = syscall.LoadLibrary("kernel32.dll")
getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
user32, _ = syscall.LoadLibrary("user32.dll")
messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
看出来没,这和C\C++调用一个微软的Api如出一辙。都是获取了MessageBox在内存的地址,然后
func MessageBox(caption, text string, style uintptr) (result int) {
// var hwnd HWND
ret, _, callErr := syscall.Syscall6(uintptr(messageBox), 4,
0, // HWND
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), // Text
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), // Caption
style, // type
0,
0)
if callErr != 0 {
abort("Call MessageBox", int(callErr))
}
result = int(ret)
return
}
关看代码就可以知道GO调用MessageBox,和C、c++进行了完全一样的步骤。syscall.Syscall6到底做了点什么~ 想必也就是简单的获取syscall.Syscall6的第一个参数 messbox在windows内存中位置(二进制代码段的位置),获取第二个参数,这个表明了被调用的MessageBox有四个参数,也就是push四次,然后分别取出后面的四个参数进行压杖,最后call
push style
push caption
push text
push 0
CALL messageBox
不过我好奇的是,我简单的弹一个messagebox,但是这个进程却启动了6个线程
抛开搜狗输入法注入可能启动的线程不说,起码在·GO编译出来的代码中,也就是
内存偏移 messagebox.exe+0X4af80和messagebox.exe+0X4b240这个地方的线程,理论上讲是Go语言生成的。
莫非这几个线程就是为了Go语言高并发设计的线程池?
我们以后慢慢来深入学习,看看Go语言葫芦里到底有什么药。
有疑问加站长微信联系(非本文作者)