‘ .NET开发 ’ category archive

.NET开发常见问题两则

178 views 九月 22, 07 by Timothy

一、关于DateTime
在将DateTime类型,插入到数据库的时候,最容易出现的一种错误:
“SqlDateTime 溢出。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间”
原因是我们在取DateTime.MinValue的值,并插入到数据库的时候,DateTime.MinValue值范围和数据库DateTime类型数据范围不一致造成的。数据库中,DateTime类型字段,最小值1/1/1753 12:00:00,而.NET Framework中,DateTime类型,最小值为1/1/0001 0:00:00,显然,超出了Sql的值的最小范围,导致数据溢出的错误。

解决方法:使用System.Data.SqlTypes.SqlDateTime.MinValue替代System.DateTime类型,这样SqlDateTime的MinValue和Sql中DateTime的范围吻合,就不会再出现以上的错误了。

二、关于跨线程调用控件的问题
在.NET 2.0中,我们常常需要在新建的线程,比如一个工作线程中访问UI控件,程序编译没有任何错误,但是在运行的时候,会抛出异常:InvalidOperationException,并提示消息:“从不是创建控件 control name 的线程访问它。”
原因是因为:访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问控件非常重要。.NET Framework 有助于在以非线程安全方式访问控件时检测到这一问题。

我们看看有问题的代码:建立新线程,并试图在线程中跨线程调用UI控件
[code]
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(TestFunc));
thread.IsBackground = true;
thread.Start();
}

private void TestFunc()
{
Thread.Sleep(3000);
label1.Text = "ok!";
}

[/code]

这样在运行的时候,就会抛出InvalidOperationException异常。

解决方法:
方法1.关闭跨线程调用控件的检查,来屏蔽掉此异常
需要将Control.CheckForIllegalCrossThreadCalls 设为 false即可。(不推荐)

方法2.使用Control类的Invoke和BeginInvoke
为什么使用Invoke和BeginInvoke可以解决问题呢?因为Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。而控件也是在UI线程,所以不存在跨线程调用控件的问题。于是我们有了改进的代码:

[code]
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(TestFunc));
thread.IsBackground = true;
thread.Start();
}

private void TestFunc()
{
Thread.Sleep(3000);
this.Invoke(new SetLabel(SetLabelText), new string[] { "ok!" });
}

private delegate void SetLabel(string s);

private void SetLabelText(string s)
{
label1.Text = s;
}

[/code]

建立一个委托,调用Control类的Invoke方法,让UI线程去执行委托实例化的方法。这样就不会出现异常了。

PJBlog恶意广告POST漏洞之测试与修复

187 views 八月 30, 07 by Timothy

今天在网上找了一个Vista的皮肤,赶紧给我的BLOG换上,漂亮了许多,呵呵。
最近BLOG上,广告多得吓人,特别是在文章的评论和留言本里面,真是无孔不入的广告。由于偶比较痛恨这些广告,手动删除也不是办法,整页整页的广告评论和留言,多则上百条。而且手动在管理界面删除,也只是一个治标不治本的办法。
据寡人分析[biggrin],可能是评论和留言的post环节不够强悍,导致垃圾广告有孔而入。不过这个BLOG的评论和留言都是有验证码的,评论的POST对应于blogcomm.asp文件,评论的页面,通过指向GetCode.asp,获取验证码图片,并在Session中保存该验证码,用以和用户输入的验证码比对。
那么如果要达到用程序,自动提交垃圾广告,可以想到的方法有两种:
1.用程序识别图片验证码,获取其内容,然后模拟POST。不过这个比较高难,要程序识别图片中的数字,需要图形识别的知识。
2.绕过验证码的过程,直接POST。这个要根据具体的漏洞而定。

于是随手在google上搜索了一下,PJBlog还真有这个漏洞。[eek]

具体的漏洞描述如下:
blogcomm.asp文件对验证码判断不严格。
如果用户没有请求过GetCode.asp文件,那么服务器端Session里面的GetCode值为空,而用户提交的数据里面验证码也为空,这样刚好空等于空,反而通过了验证码验证。

查看blogcomm.asp源码,在Line 94行有这样的情况。

为了验证这个漏洞是否存在,我们可以自己动手测试一下,用程序模拟POST一次。就拿偶的BLOG做实验吧。首先,随便打开一个文章,启动网络抓包工具,(这里我用的是WSE–WinSocketExpert),随便敲入几个字,查看捕获下来的网络包。我们会发现,POST的数据格式是这样的:

username=Timothy&password=&Message=PostData&logID=171&action=post&submit2=%E5%8F%91%E8%A1%A8%E8%AF%84%E8%AE%BA

username 是评论者名称
password 是密码(游客不需要密码)
logID 就是文章编号
Message 就是评论内容了,垃圾广告最关注的就是这个……
action 是一个隐藏的field,值为post,这个可以在页面上通过查看源码看到
submit2 后面的码,转换成中文,其实就是“发表评论”,同样参考评论页面源码

POST的结构知道了,下面我们用程序来模拟POST一下,看漏洞是否存在,测试代码如下:
(请慎用此部分代码,不要用于垃圾广告软件,谢谢 [cool])

[code]private void PostFunc()
{

WebClient wc = new WebClient();

string postData = "username=Timothy&password=&Message=PostData&logID=171&action=post&submit2=%E5%8F%91%E8%A1%A8%E8%AF%84%E8%AE%BA";
try
{
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
wc.UploadData("http://www.xiaozhou.net/cooldog/blogcomm.asp", "POST", Encoding.Default.GetBytes(postData));
}
catch
{
wc.Dispose();
return;
}

wc.Dispose();
}[/code]

运行此程序,可以在我的blog的编号171的文章评论中,看到下图:

看来漏洞真的存在……
这里,我们可以看到POST数据结构中,logID是可以人为改变的,也就是文章编号。如果把logID作为变量自增,测试代码外面,再套一个for循环,这个程序就成了制造垃圾广告的机器了……

找到了漏洞,得赶紧补上才行。其实我们需要修改的地方,就是在blogcomm.asp。找到94行,这里的判断,由于没有对Session进行判断才导致了此漏洞的产生。
修改方法如下:
blogcomm.asp Line:94
原代码:

IF (memName=empty or blog_validate=true) and cstr(lcase(Session("GetCode")))<>cstr(lcase(validate)) then

替换后的代码,增加对Session的判断:

IF (memName=empty or blog_validate=true) and (cstr(lcase(Session("GetCode")))<>cstr(lcase(validate)) or IsEmpty(Session("GetCode"))) then

大功告成了……[cool]睡觉去……

动手DIY,给你的MSN机器人加上远程控制功能

146 views 八月 28, 07 by Timothy

MSN机器人是一个比较好玩的东东,通过第三方提供的SDK开发包,允许我们开发自己的MSN机器人,实现一些有趣的功能。比如自动聊天等等。

进行MSN机器人开发,需要你首先申请一个MSN帐号,然后去http://sp.incesoft.com/index注册帐号,把你的MSN机器人挂在平台上面。然后下载SDK,开发机器人逻辑。
开发出来的机器人程序,会主动和第三方的平台登录连接,这个时候,你的机器人就可以运行了。

运行的方式:
1.机器人程序–>登录incesoft服务器—>MSN机器人上线
2.MSN客户端向机器人发起聊天—>incesoft接收到数据包—>转发给你的机器人程序

这样,MSN客户端发给你的机器人的信息,就传递到你的机器人程序了,而你可以根据不同的信息,进行不同的动作,这些动作,都是在incesoft提供的SDK里面封装好了。

通过这种运行方式,要加入远程控制功能,是非常方便的,我们可以将登录MSN机器人程序的机器,作为受控端。而且还有一个好处,就是你不用去关心IP变化,只要机器人上线了,就可以开始控制了,这也是用MSN机器人实现的优势。

远程控制,流程如下:
1.被控制机器,运行MSN机器人程序,登录MSN机器人
2.管理机器,发送OP指令给MSN机器人,获取OP控制权限
3.管理机器,发送控制指令
4.被控制机器端,响应指令,做出回应

好像被我说复杂了,其实实现起来非常的简单。

需要准备的工作,申请MSN帐号,然后去http://sp.incesoft.com/index 申请一个帐号,挂上你的MSN帐号。然后下载SDK包,进行开发。

下面是我实现的一个简单的远程控制功能

1.和机器人交互,出现命令菜单

这个时候需要你进入OP模式,才能进行远程控制的操作

2.输入OP密码,这个时候,就获取了OP控制权限,可以控制远程机器了

3.远程控制示例,列举进程列表

4.杀掉指定进程

5.退出OP模式

关机和重启,功能是实现了的,这里就不演示了,呵呵

放上源代码,大家可以下载下来试试

点击下载此文件

调试运行的时候,请替换RobotService.cs Line:144 行的用户名和密码,也就是你在incesoft注册的帐号和密码。

.NET中关机、重启的类

102 views 六月 30, 07 by Timothy

这是一个封装的在.NET下面实现关机和重启的一个类,其实就是直接引用了Win32 API。
业余的时间,写了个MSN机器人,后来突发灵感,想加入远程控制主机的功能,包括重启和关机,于是用上了这个类。待MSN机器人开发完成,放出源码,hoho。

//关机、重启计算机 封装类
using System;
using System.Collections.Generic;
using System.Text;
using System;
using System.Runtime.InteropServices;

namespace MyRobot
{

class ShoutDown
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}

[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool ExitWindowsEx(int flg, int rea);

internal const int SE_PRIVILEGE_ENABLED = 0×00000002;
internal const int TOKEN_QUERY = 0×00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0×00000020;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const int EWX_LOGOFF = 0×00000000;
internal const int EWX_SHUTDOWN = 0×00000001;
internal const int EWX_REBOOT = 0×00000002;
internal const int EWX_FORCE = 0×00000004;
internal const int EWX_POWEROFF = 0×00000008;
internal const int EWX_FORCEIFHUNG = 0×00000010;

public static void DoExitWin(int flg)
{
bool ok;
TokPriv1Luid tp;
IntPtr hproc = GetCurrentProcess();
IntPtr htok = IntPtr.Zero;
ok = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
tp.Attr = SE_PRIVILEGE_ENABLED;
ok = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
ok = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
ok = ExitWindowsEx(flg, 0);
}
}
}

利用IIS作为宿主 发布你的WCF Service

169 views 三月 16, 07 by Timothy

最近公司的一个需求,涉及到WCF开发。在网上找了些资料,大都是利用单独的应用程序、或者Windows服务作为WCF Service的host。其实WCF还提供一种方式,和以前的Remoting比较类似,就是基于IIS发布你的WCF Service。

大致部署步骤如下:

1.编译好WCF Service的Class Library,确保没有错误。
2.建立.svc文件,内容格式如下:

1<%@ServiceHost language=c# Debug="true" Service="CommonService.MailService" %>   

 
这里的Service,是你的Service名称,及其所属命名空间.

为了确保IIS能正确识别.svc文件,需要在IIS属性中检查,如果没有.svc类型,需要手动添加,如图:

3.在IIS发布WCF Service,将其目录设置为Web共享,并注意在IIS中,为该虚拟目录打开匿名访问的权限。
4.在工程中,添加Web.config文件。这里需要建立WCF Service服务段的配置信息,我们可以直接利用MS提供的配置工具方便进行配置,如图:

打开配置工具,根据配置向导,选择好Service Type 和Contract信息。在选择服务通讯方式的时候,我们需要选择http通讯方式(因为我们服务的宿主是IIS,所以应选择http方式)。在EndPoint中,填入Endpoint的地址。再选择添加一个Endpoint,address为mex,类型为mexHttpBinding,Contract填入IMetadataExchange。

5.为了能在IIS中测试发布的效果,我们需要允许从客户端通过http方式获取元数据,这样的选项WCF默认是false,所以我们还需要一点小设置:
在Service Behavior节点,单击右键,新建一个Service Behavior,单击Add按钮,添加一个Extention Position,名称为serviceMetadata,如图:

并在上面双击,在窗口中,把HttpGetEnabled选项设置为true,如图:

一切的准备工作就绪后,我们就可以通过IIS来访问测试我们的WCF Service了。如下图:

红色框中的部分,是我们设置了HttpGetEnabled的结果,否则是不会出现这一行的,它允许我们从客户端以WSDL方式获取其源数据。
小结一下:采用IIS作为宿主程序,方便之处就在于你不必专门为WCF Service再去建立一个host文件。

Page 4 of 512345