您的位置:首页 > 编程语言 > Go语言

Go语言探索第一天,学习笔记

2016-06-25 14:22 555 查看
        已经在大数字做了三年的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[/b]

编译 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语言葫芦里到底有什么药。

       
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: