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

eff_vector · · 3317 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

        已经在大数字做了三年的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语言葫芦里到底有什么药。

       






有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:eff_vector

查看原文:Go语言探索第一天,学习笔记

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3317 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传