纯汇编如何获得LoadLibrary地址和实现GetProcAddress? 100分求教---***

Happy0403 2010-09-20 01:33:46
我有代码,可是不懂汇编,看不懂。
想做个远程程序注入的,不想靠Dll,想直接写代码,不过如果用C++直接写成程序的话,代码太大。
所以我想到了用汇编实现一些简单的代码。

哪位牛人帮我解释下一下代码:

函数:(实现GetProcAddress的功能)
00400164 60 pushad
00400165 8B6C24 24 mov ebp,dword ptr ss:[esp+24]
00400169 8B45 3C mov eax,dword ptr ss:[ebp+3C]
0040016C 8B7C05 78 mov edi,dword ptr ss:[ebp+eax+78]
00400170 01EF add edi,ebp
00400172 8B4F 18 mov ecx,dword ptr ds:[edi+18]
00400175 8B5F 20 mov ebx,dword ptr ds:[edi+20]
00400178 01EB add ebx,ebp
0040017A 49 dec ecx
0040017B 8B348B mov esi,dword ptr ds:[ebx+ecx*4]
0040017E 01EE add esi,ebp
00400180 31C0 xor eax,eax
00400182 99 cdq
00400183 AC lods byte ptr ds:[esi]
00400184 84C0 test al,al
00400186 74 07 je short SmallLea.0040018F
00400188 C1CA 0D ror edx,0D
0040018B 01C2 add edx,eax
0040018D ^ EB F4 jmp short SmallLea.00400183
0040018F 3B5424 28 cmp edx,dword ptr ss:[esp+28]
00400193 ^ 75 E5 jnz short SmallLea.0040017A
00400195 8B5F 24 mov ebx,dword ptr ds:[edi+24]
00400198 01EB add ebx,ebp
0040019A 66:8B0C4B mov cx,word ptr ds:[ebx+ecx*2]
0040019E 8B5F 1C mov ebx,dword ptr ds:[edi+1C]
004001A1 01EB add ebx,ebp
004001A3 032C8B add ebp,dword ptr ds:[ebx+ecx*4]
004001A6 896C24 1C mov dword ptr ss:[esp+1C],ebp
004001AA 61 popad
004001AB C3 retn


调用代码:

004001AC 31DB xor ebx,ebx
004001AE 64:8B43 30 mov eax,dword ptr fs:[ebx+30]
004001B2 8B40 0C mov eax,dword ptr ds:[eax+C]
004001B5 8B70 1C mov esi,dword ptr ds:[eax+1C]
004001B8 AD lods dword ptr ds:[esi]
004001B9 8B40 08 mov eax,dword ptr ds:[eax+8]
004001BC 5E pop esi
004001BD 68 8E4E0EEC push EC0E4E8E
004001C2 50 push eax
004001C3 FFD6 call esi ; 汇编实现的GetProcAddress
004001C5 66:53 push bx
004001C7 66:68 3332 push 3233
004001CB 68 7773325F push 5F327377
004001D0 54 push esp
004001D1 FFD0 call eax ; LoadLibrary("ws2_32");
004001D3 68 CBEDFC3B push 3BFCEDCB
004001D8 50 push eax
004001D9 FFD6 call esi ; 汇编实现的GetProcAddress
004001DB 5F pop edi
004001DC 89E5 mov ebp,esp
004001DE 66:81ED 0802 sub bp,208
004001E3 55 push ebp
004001E4 6A 02 push 2
004001E6 FFD0 call eax ; ws2_32.WSAStartup(2);
004001E8 68 D909F5AD push ADF509D9
004001ED 57 push edi
004001EE FFD6 call esi ; SmallLea.00400164
...全文
1333 13 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
stolen007 2011-04-14
  • 打赏
  • 举报
回复

add edi, ebx ;edi = API NAME

push ecx
mov ecx, [esp + 4 + 4]
Happy0403 2010-09-30
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 blueapple1987 的回复:]

引用 5 楼 renxu350 的回复:

引用楼主 weizehua 的回复:
我有代码,可是不懂汇编,看不懂。
想做个远程程序注入的,不想靠Dll,想直接写代码,不过如果用C++直接写成程序的话,代码太大。
所以我想到了用汇编实现一些简单的代码。


在确定目标被注入进程装载 kernel32.dll 的前提下,在 Windows XP 环境下,LoadLibraryW 的装……
[/Quote]

恩,我想要的。
Happy0403 2010-09-30
  • 打赏
  • 举报
回复
多谢大家的回答,不过我乍一看,不懂。。。。
renxu350 2010-09-29
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 blueapple1987 的回复:]

你要是不会 就不要误导别人好不好?
http://bbs.pediy.com/showthread.php?t=121226
[/Quote]

你既是KANXUE高手,为何还来这里显摆?
我等未有学习过此项技术,自知是菜鸟级别,才做此菜鸟回答,OK ?
对看雪早已经久仰已久,
虽然你技术高超,但你的言语显示你缺乏真正高手的涵养,
你幸灾乐祸于别人没学过,而自己却学过的东西,
你是在自己自我贬低你自己一个KANXUE高手的人品,
你只能算是人品低下的技术高手,
就是这100分全给了你又如何 ?
就算全世界服务器的操作系统全部被你挂了一次马又如何 ?
我鄙视这种人品低下的技术高手 !
拜托你言语能否不要隐藏着刺人的言语 OK ?!
六月的兔子 2010-09-29
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 renxu350 的回复:]

引用楼主 weizehua 的回复:
我有代码,可是不懂汇编,看不懂。
想做个远程程序注入的,不想靠Dll,想直接写代码,不过如果用C++直接写成程序的话,代码太大。
所以我想到了用汇编实现一些简单的代码。


在确定目标被注入进程装载 kernel32.dll 的前提下,在 Windows XP 环境下,LoadLibraryW 的装载地址是固定不变的,为 7C80ACD3H ,如……
[/Quote]


你要是不会 就不要误导别人好不好?
http://bbs.pediy.com/showthread.php?t=121226
mxxgt 2010-09-27
  • 打赏
  • 举报
回复
;注意masm编译,注意这个程序不能直接运行,编译完成后od加载code3之前运行一次是加密,运行完dump出来就是shellcode了!
.386p
.model flat, stdcall
.code
start:
assume fs:flat, gs:flat
;这里直接写代码

;------------------------B.j.H's split-line-----------------------------------
;首先建立一个在shellcode中需要用到的字符表他应该包括
;LoadLibraryA
;user32
;MessageBoxA
;ExitProcess
;B.J.H 当然为了弹出的Msgbox有个性可以添加这样一字符串,用来弹框框
;这些字符统统压入堆栈以便调用!
;所以我们代码的前面是
;------------------------B.j.H's split-line-----------------------------------
push 0048h ;B.J.H
push 2e4a2e42h ;
push 00737365h ;ExitProcess
push 636f7250h
push 74697845h
push 0041786fh ;MessageBoxA
push 42656761h
push 7373654dh
push 00323372h ;user32
push 65737500h
push 41797261h ;LoadLibraryA
push 7262694ch
push 64616f4ch
mov edx,esp ;保存字符串首地址
;上面是一个函数表!注意压入的字符格式,注意堆栈是倒过来的!慢慢调试可以感觉出来的!
;最后一据代码是保存字符串表的的入口(也就是首地址)
;------------------------B.j.H's split-line-----------------------------------
;获得Kernel的基地址(这一段很多地方都能找到!)不做解释了!
xor eax,eax
mov eax,dword ptr FS:[030h]
mov eax,DWORD PTR [eax+0ch]
mov esi,DWORD PTR [eax+01ch]
lodsd
mov eax,dword ptr [eax+8h]
;------------------------B.j.H's split-line-----------------------------------
;现在eax中存放的就是kernel32的基地址了!
;当处到这里我就不知道该怎么出来了!得到基地址到底有什么用呢!不知道!呵呵!时间久了!
;忙忙的阅读一些资料!自然而然的就懂了!...我不是那种一看资料就明白的那种具有潜质的大
;鸟,只是一点一点体会的小菜鸟!
;下面先写一个调用就是
;------------------------B.j.H's split-line-----------------------------------
push eax ;保存kernel32.dll基地址
push edx ;传入需要查询函数名地址
push 0ch ;函数名长度
call getapi ;调用函数得到函数入口
;------------------------B.j.H's split-line-----------------------------------
pop ebx ;弹出堆栈里的的函数名地址(是之前建立的)
add ebx,0dh ; 加上字符长度得到下一个需要使用的字符串的
push ebx ;参数"user32"
call eax ;调用LoadLibraryA("user32"),加载
;user32.dll,且eax中是从函数调用返回的user32的基地址
;------------------------B.j.H's split-line-----------------------------------
add ebx,07h ; 继续得到下一个需要使用的字符串。下面的几个调用不详细说了... ...
push ebx ;
push 0bh ;
call getapi ;调用getaddr函数获取MessageBoxA函数地址.
;------------------------B.j.H's split-line-----------------------------------
pop ebx ;
add ebx,018h ;
push 0h ;
push ebx ;
push ebx ;
push 0h ;
call eax ;调用MessageBoxA
;------------------------B.j.H's split-line-----------------------------------
mov edx,0ch ;
pop eax ;
sub ebx,edx ;
push ebx ;
push edx ;
call getapi ;调用getaddr函数获取exitprocess函数地址.
call eax ;调用exitprocess
;------------------------B.j.H's split-line-----------------------------------
;下面这个才是重点!(个人认为)
;写一个根据dll的基地址查找API函数入口 的函数方便调用
;函数说明:此函数包括两个传入参数,一个是基地址,另一个是需要查询的函数名字符串首地址
;------------------------B.j.H's split-line-----------------------------------
getapi:
mov ebx,eax ;eax存放的传入的基地址
add eax,03ch ;定位PE头位置地址
mov eax,dword ptr [eax] ;获得PE头偏移地址
add eax,ebx ;计算PE头VA
cmp dword ptr [eax],00004550h ;验证PE文件的合法性
jne Err ;不合法跳转
mov eax,dword ptr [eax+078h] ;导出表地址获得
add eax,ebx ;计算导出表入口VA
push eax ;保存导出表入口VA
mov ecx,eax ;令ecx指向导出表
mov ecx,dword ptr [ecx + 014h] ;找出导出表中函数个数作为循环值
mov eax,dword ptr [eax + 020h] ;找出函数名字符串地址表的偏移
add eax,ebx ;计算函数名字符串地址表的VA
push ebp ;保存ebp寄存器,寄存器不够用,借用一下,呵呵!
mov ebp,eax ;ebp保存函数名字符串地址表的VA
xor edx,edx ;edx清0用于存放函数索引

LoopFind:
push ecx; ;保存ecx 循环次数
mov eax,dword ptr[eax] ;获取函数名字符串偏移
add eax,ebx ;计算函数字符串VA
mov edi,eax ;把VA赋值给edi 准备比较
mov esi,dword ptr [esp + 014h] ;这个地方要算好了!函数内部有3个push,每个push为4个字节一个12个字节
;字符串地址放在call外部倒数第二个push(这个自己用控制好第几个参数是自己定的)
;也就是说从push 字符串地址到这个命令行之间有16个字节被push进入栈中。是不是就是+10H呢
;注意我们这里用了一个函数,不是jmp,函数调用的时候会有一个push eip用于返回!
;所以我们在计算的时候这个push不能忘,最后计算得到esp+14h中所放的就我们要查的函数名字符的地址
mov ecx,dword ptr [esp + 010h] ; 计算同上,这里是给ecx赋值,函数名的长度。ecx被改变了
;(后面,在loop命令之前要恢复的ecx,这个是计数器,硬性规定,呵呵!)
cld ;
repz cmpsb ;字符串比较 esi 和 edi 比较
jne FindNext ;比较,如果不是,则取下一个函数

add esp,4 ;找到往下执行 相当与pop ecx。无关紧要了!
mov eax,dword ptr [esp + 04h] ;恢复导出函数表入口
mov eax,dword ptr [eax + 01ch] ;获得函数地址表入口偏移
;我在这里缺少了一步,大多数情况不会有影响,具体的是哪一步,
;深究的同志可以看看关于函数导出表的函数查询方式
add eax,ebx ;计算函数地址表入口VA
shl edx,2 ;函数索引*函数地址(默认为4个字节) 鉴戒别人的,很妙的一招相当与乘以4
add eax,edx ;函数地址表基址+(函数索引)
mov eax,dword ptr[eax] ;获得函数入口地址偏移
add eax,ebx ;计算VA
jmp Found

FindNext:
inc edx ;计数器加一
add ebp,4h ;函数名字符串地址表的VA指向下一个函数名地址
mov eax,ebp ; 函数名地址的VA赋值到eax
pop ecx ;恢复ecx 循环次数
loop LoopFind ;loop 继续循环查找

Err:
xor eax,eax ;没有找到,或者出错,eax清理。

Found:
pop ebp ;恢复ebp
pop ecx ;不能再恢复eax了!弹到ecx好了!
ret 4 ; 返回 且 add esp 4
;这个是因为我们调用完函数时需要利用之前我们自己建立函数名字符表。
end start
jhlong 2010-09-22
  • 打赏
  • 举报
回复
楼主研究一下TEB PEB的结构,另外研究一下PE文件格式
这段代码的细节我也不太记得清了,以前仔细分析过,现在都是拿来直接用了

大致的思路是查找PEB结构里的模块链表,总共有3个链表,这里用到的是按模块加载顺序的那条
链表第一个节点值NTDLL.DLL, 第二个节点是KERNEL32.DLL
定位到KERNEL32.DLL模块首地址
再去通过函数名称的一个自己实现的简单的HASH遍历导出表,(在CALL ESI里)获取到目标函数的地址
我记性不好,可能有不对的地方

这段代码和地址无关,可以放在任意地方执行,楼主放心用吧

《0day:软件漏洞分析技术》这本书里有很详细的解释,楼主可以去买一本参考一下
Happy0403 2010-09-22
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 jhlong 的回复:]

楼主随便去找段shellcode参考一下吧,网上很多
[/Quote]

这就是从ShellCode里抄出来的,不过我看不懂。
renxu350 2010-09-22
  • 打赏
  • 举报
回复

7C80ACDF E8 0D6EFFFF call LoadLibraryExW


帮你分析一下这句你就知道完全手写代码是不可能的,
E8 0D6EFFFF 是相对跳转,
FFFF6E0DH 是负数,
也就是向之前的代码 CALL,
我们来计算一下,
FFFF6E0DH - 1H = FFFF6E0CH
二进制取反 = 000091F3H
也就是 7C80ACDFH 这一行将会从下一条指令开头算起,
从 7C80ACE4H 向后 000091F3H 个位置,
7C80ACE4H - 000091F3H = 7C801AF1H
7C801AF1H 正好是 LoadLibraryExW 的地址,
CALL 指令将会 CALL 到 LoadLibraryExW,
你如果把这些代码直接拷贝,
这一行将会 CALL 一个什么都不是的代码,
所也建议LZ不要手写代码。
renxu350 2010-09-22
  • 打赏
  • 举报
回复
[Quote=引用楼主 weizehua 的回复:]
我有代码,可是不懂汇编,看不懂。
想做个远程程序注入的,不想靠Dll,想直接写代码,不过如果用C++直接写成程序的话,代码太大。
所以我想到了用汇编实现一些简单的代码。
[/Quote]

在确定目标被注入进程装载 kernel32.dll 的前提下,在 Windows XP 环境下,LoadLibraryW 的装载地址是固定不变的,为 7C80ACD3H ,如果你不想依赖目标进程的装载 kernel32.dll 的与否,你可以直接拷贝 LoadLibraryW 的代码,不过估计这样不太可能实现,LoadLibraryW 在内部又 CALL 了 kernel32.dll 的LoadLibraryExW,LoadLibraryExW 在内部又 CALL 了 ntdll.dll 的一些函数,所以LZ想完全手写代码是不现实的,手写 GetProcAddress 的代码也是不现实的,GetProcAddress 在内部也 CALL 了 ntdll.dll 的一些函数,所以目标进程也需要装载 ntdll.dll,所以你贴出的代码就没必要去解释其含义了。

下面是 LoadLibraryW 的反汇编码:


7C80ACD3 > 8BFF mov edi, edi
7C80ACD5 55 push ebp
7C80ACD6 8BEC mov ebp, esp
7C80ACD8 6A 00 push 0
7C80ACDA 6A 00 push 0
7C80ACDC FF75 08 push dword ptr [ebp+8]
7C80ACDF E8 0D6EFFFF call LoadLibraryExW
7C80ACE4 5D pop ebp
7C80ACE5 C2 0400 retn 4


下面是 GetProcAddress 的反汇编码:


7C80AC28 > 8BFF mov edi, edi
7C80AC2A 55 push ebp
7C80AC2B 8BEC mov ebp, esp
7C80AC2D 51 push ecx
7C80AC2E 51 push ecx
7C80AC2F 53 push ebx
7C80AC30 57 push edi
7C80AC31 8B7D 0C mov edi, dword ptr [ebp+C]
7C80AC34 BB FFFF0000 mov ebx, 0FFFF
7C80AC39 3BFB cmp edi, ebx
7C80AC3B 0F86 571C0000 jbe 7C80C898
7C80AC41 57 push edi
7C80AC42 8D45 F8 lea eax, dword ptr [ebp-8]
7C80AC45 50 push eax
7C80AC46 FF15 8812807C call dword ptr [<&ntdll.RtlInitString>] ; ntdll.RtlInitString
7C80AC4C 8D45 0C lea eax, dword ptr [ebp+C]
7C80AC4F 50 push eax
7C80AC50 6A 00 push 0
7C80AC52 8D45 F8 lea eax, dword ptr [ebp-8]
7C80AC55 50 push eax
7C80AC56 6A 00 push 0
7C80AC58 FF75 08 push dword ptr [ebp+8]
7C80AC5B E8 C2ECFFFF call 7C809922
7C80AC60 50 push eax
7C80AC61 E8 B7FFFFFF call <jmp.&ntdll.LdrGetProcedureAddress>
7C80AC66 85C0 test eax, eax
7C80AC68 0F8C DE830000 jl 7C81304C
7C80AC6E 6A 00 push 0
7C80AC70 FF75 08 push dword ptr [ebp+8]
7C80AC73 E8 AAECFFFF call 7C809922
7C80AC78 3945 0C cmp dword ptr [ebp+C], eax
7C80AC7B 0F84 12600300 je 7C840C93
7C80AC81 8B45 0C mov eax, dword ptr [ebp+C]
7C80AC84 5F pop edi
7C80AC85 5B pop ebx
7C80AC86 C9 leave
7C80AC87 C2 0800 retn 8

小魔菇 2010-09-21
  • 打赏
  • 举报
回复
不会这么高深的东东 帮顶
jhlong 2010-09-20
  • 打赏
  • 举报
回复
楼主随便去找段shellcode参考一下吧,网上很多
红烧肉 2010-09-20
  • 打赏
  • 举报
回复
嗯。不明白你说的不靠DLL是说不加载kernel32.dll的意思么?应该所有的应用程序都会加载到这个动态库吧,我是说再windows xp 系统,其它的不晓得

21,497

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧