Q:

Is overloading of the == operator necessary here?

I think that the overloading in code below of the == is unnecessary in the manner shown since == already compares references if not overloaded. Please advise me on the manner. It should rather be done with the one parameter Equals and the null comparison included separately?
public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override bool Equals(object param)
    {
    // If the cast is invalid, the result will be null
    Student student = param as Student;

    // Check if we have valid not null Student object
    if (student == null)
    {
        return false;
    }

    // Compare the reference type member fields
    if (!Object.Equals(this.Name, student.Name))
    {
        return false;
    }

    // Compare the value type member fields
    if (this.Age != student.Age)
    {
        return false;
    }
    return true;
    }

    public static bool operator ==(Student student1, Student student2)
    {
        return Student.Equals(student1, student2);
    }

    public static bool operator !=(Student student1, Student student2)
    {
        return !(Student.Equals(student1, student2));
    }

  ...

  }

A:

I think that the overloading in code below of the == is unnecessary in the manner shown since == already compares references if not overloaded.

Yes, but the point is that because the operator has overloaded, you can compare for value equality rather than reference identity. For example:
Student x = new Student { Name = "Jon", Age = 37 };
Student y = new Student { Name = "Jon", Age = 37 };

Console.WriteLine(x == y); // Prints True

Without the operator overloading, the above code would print False, because the values of x and y refer to different objects.
That's sometimes more convenient than explicitly calling the Equals method.
So while it's not strictly necessary to overload == here (as the same results can be achieved in other ways), it does affect the behaviour. It's not a good idea to overload == for all types by any means, but it can make things a lot simpler for some types. I'm very glad that string overloads ==, for example. A discussion about when it is a good idea to overload == is out of scope for this answer, fortunately - it's a matter of some debate, for starters. I do it relatively rarely for classes, but almost always for value types. (It's pretty rare to write a custom value type to start with.) The general grey area is immutable reference types...
Be aware that the overload is only applied when the operands are of the right compile-time type though. For example:
Student x = new Student { Name = "Jon", Age = 37 };
object y = new Student { Name = "Jon", Age = 37 };

Console.WriteLine(x == y); // Prints False

Here the overload isn't used because the compile-time type of y is object, not Student.
As a different matter, the fact that this is a mutable class which overrides Equals and therefore presumably GetHashCode is a matter of some concern. It's generally a bad idea to override Equals in classes where instances can change in a way that affects equality. It doesn't play well with collections which use equality and hashing. For example:
var dictionary = new Dictionary<Student, string>();
var student = new Student { Name = "Jon", Age = 37 };
dictionary[student] = "foo";
Console.WriteLine(dictionary.ContainsKey(student)); // True
dictionary.Name = "Bob";
Console.WriteLine(dictionary.ContainsKey(student)); // False
Console.WriteLine(dictionary.Keys.First() == student); // True!

Because the name has changed, the hash code has changed (I'm assuming a fairly simple hash code implementation which uses name and age). That means the normal hash check will fail, even though the reference is still in the dictionary.
It's okay if you don't mutate the key after you've added it to the dictionary, but it makes such types a bit more accident-prone, so to speak.

